¿Qué es un árbol de decisión?
Un árbol de decisión es un mapa de posibles resultados en una serie de decisiones relacionadas. Un diagrama que muestra la probabilidad estadística o determina un curso de una acción. Muestra a los analistas y, a los que toman las decisiones, qué pasos deben tomar y cómo las diferentes elecciones podrían afectar todo el proceso. Todo ello soportado en datos.
Los árboles de decisión comienzan con un nodo, del cual salen otros en función de las opciones que se presenten, y de cada una de estas, otros. Existen tres tipos diferentes de nodos:
Nodos de decisión: Se le representa con un cuadrado y muestra una decisión que se tomará.
Nodos de probabilidad: Está representado por un círculo y muestra las probabilidades de ciertos resultados.
Nodos terminales: Son de forma triangular, y muestra el resultado definitivo de una ruta de decisión.
Otros conceptos importantes:
*Otro concepto importante a tener en cuenta son las
Ramificaciones. Estas se representan por líneas entre los nodos e indican un posible resultado o acción dentro del árbol.
Hojas: Las hojas son las terminaciones de todas las ramas (el número de triángulos o nodos terminales)
¿Cómo hacemos un árbol de decisión?
Para realizar un árbol de decisión, podemos seguir los siguientes pasos:
Comenzamos con la decisión principal: Comenzaremos dibujando un cuadro que será el nodo principal. Luego, hacia la derecha comenzamos a hacer las ramificaciones, que representan las posibles decisiones y las etiquetamos.
Agregamos a cada ramificación nodos de decisión y probabilidad: esto hace que se expanda el árbol del siguiente modo:
Si otra decisión es necesaria, entonces colocamos un cuadro que representa un nodo de decisión.
Si el resultado es incierto, dibujamos un círculo (que representa los nodos de probabilidad), cuando tenemos un evento en el cual conocemos la probabilidad.
Si el problema por medio de esa ramificación ya finaliza ponemos un triángulo
Desde cada nodo de decisión, dibuja soluciones posibles con ramificaciones. Desde cada nodo de probabilidad, dibuja líneas que representen los resultados posibles. Si deseas analizar tus opciones de forma numérica, incluye la probabilidad de cada resultado y el costo de cada acción.
- Continúa con la expansión hasta que cada línea alcance un extremo, lo que significa que no hay más decisiones que tomar o resultados probables que considerar. Luego, asigna un valor a cada resultado posible. Puede ser una puntuación abstracta o un valor financiero. Agrega triángulos para indicar los extremos.
Con un árbol de decisión completo, ya estás listo para comenzar a analizar la decisión que enfrentas.
Ventajas y desventajas
Los árboles de decisión siguen siendo populares por razones como las siguientes:
Son muy fáciles de entender
Pueden ser útiles con o sin datos fehacientes, y cualquier dato requiere una preparación mínima
Se pueden agregar nuevas opciones a los árboles existentes
Su valor al seleccionar la mejor de numerosas opciones
Se combinan fácilmente con otras herramientas de toma de decisiones
Podemos encontrar un valor esperado y optimizarlo para encontrar la mejor decisión.
Sin embargo, los árboles de decisión pueden volverse excesivamente complejos. En esos casos, un diagrama de influencia más compacto puede ser una buena alternativa. Los diagramas de influencia se enfocan en los objetivos, las entradas y las decisiones fundamentales.
Ejemplo de árbol de creación decisión Petro Enterprises
Para entender la construcción de un árbol hagamos un ejemplo:
Petro Enterprises es una compañía de petróleos de Texas. La compañía Petro tiene una opción intransferible a corto plazo para perforar en una determinada parcela de tierra. La opción es el único acuerdo comercial en el que la empresa está involucrada ahora o que esperar considerar entre ahora y el 31 de diciembre de 1967, momento en el que se terminaría la perforación si se ejerciera la opción.
Dos recientes perforaciones en seco en otros lugares han reducido los activos líquidos netos de la compañía Petro a 130.000 dólares, y William Snyder, presidente y principal accionista, debe decidir si Petro debe ejercer su opción o dejarla expirar. La opción expirará dentro de dos semanas si no se inicia la perforación para entonces.
Snyder tiene tres opciones posibles:
Perforar inmediatamente
Pagar para que se realice una prueba sísmica en los próximos días, y luego, en función del resultado de la prueba, decidir si se perfora o no.
Dejar que la opción expire
Una vez descritas las posibles opciones de Snyder, también debemos conocer algo sobre sus posibles consecuencias económicas. Para conservar el capital y mantener la flexibilidad, Petro subcontrata todas las perforaciones y pruebas sísmicas; además, vende inmediatamente los derechos de cualquier petróleo descubierto, en lugar de desarrollar los campos petrolíferos por sí misma. Puede hacer que la prueba sísmica se lleve a cabo con poca antelación y con tarifas de horas extras por una tarifa fija de 30.000 dólares, y el pozo puede perforarse por una tarifa fija de 100.000 dólares. Una gran compañía petrolera ha prometido que si Petro perfora y descubre petróleo, comprará todos los derechos de Petro por un precio fijo de 400.000 dólares.
Para completar la descripción, es necesario conocer las probabilidades asignadas a las distintas contingencias. El geólogo de la empresa ha examinado la geología de la región y afirma que existe una probabilidad de 0,55 de que, si se hunde un pozo, se descubra petróleo. Los datos sobre la fiabilidad de la prueba sísmica indican que si el resultado de la prueba es favorable, la probabilidad de encontrar petróleo aumentará a 0,85; pero si el resultado de la prueba es desfavorable, bajará a 0,10. El geólogo ha calculado que hay una probabilidad de 0,60 de que el resultado sea favorable si se hace la prueba. Existe una sencilla, pero importante, interrelación lógica entre estas probabilidades, si quieres conocer más acerca de ello puedes verlo en la referencia: Schlaifer, Analysis of Decisions Under Uncertainty, op. cit, Chapter 9.
Este problema de decisión que implica incertidumbre puede estructurarse en forma del árbol de decisión que se muestra a continuación. El árbol muestra las probabilidades, basadas en el juicio del geólogo de la empresa, de los distintos eventos.
Podemos ver que con las consecuencias y las probabilidades podemos ir construyendo un árbol de decisión para esta compañía.
Ejercicio
Somos trabajadores de un banco encargados de la cobranza. Queremos tomar la determinación si llamar o no llamar a los clientes en los 5 y/o 10 días de adeudos.
Tenemos alguna información importante. Por medio de un modelo de riesgos, hemos determinado la probabilidad de pago de los clientes determinada y la llamaremos \(p\). A casa cliente se le prestó una cantidad de dinero \(B\).
Nosotros podemos tomar la decisión si utilizamos a nuestros client partners para que se comuniquen con las personas o no, pero debemos de considerar que la llamada nos cuesta $8. Además, si el cliente no paga (sea que se le llame o que no se le llame), lo mandamos a una agencia externa y solo recibimos el 80% del total del préstamo.
Discute con tus compañeros el problema y realiza un árbol de decisiones para poder tomar la mejor decisión.
Los árboles de decisión en minería de datos y machine learning
Recordemos que, quizás la idea general que muchas personas tienen sobre machine learning…
Lo que es en realidad…
Como ya hemos visto con la ayuda de tidymodels y h2o, un árbol de decisión también puede usarse para ayudar a crear modelos predictivos automáticos, que pueden entrenarse mediante aprendizaje automático, en minería de datos y estadística. Conocido como lenguaje basado en árboles de decisión, estos métodos toman en consideración las observaciones sobre un elemento para predecir un valor.
En estos árboles de decisión, los nodos representan datos en lugar de decisiones. Este tipo de árbol también se conoce como árbol de clasificación. Cada ramificación contiene un conjunto de atributos o reglas de clasificación asociadas a una etiqueta de clase específica, que se halla al final de la ramificación.
Estas reglas, también conocidas como reglas de decisión, se pueden expresar en una cláusula “Si… entonces…”. Cada valor de datos o decisión forma una cláusula, de tal forma que, por ejemplo, “si las condiciones 1, 2 y 3 se cumplen, entonces el resultado X será el resultado definitivo con certeza Y”.
Cada dato adicional ayuda a que el modelo prediga de forma más precisa a qué conjunto finito de valores pertenece el asunto en cuestión. Esa información se puede usar posteriormente como una entrada en un modelo más grande de toma de decisiones.
A veces la variable predicha será un número real, como un precio. Los árboles de decisión con resultados posibles, infinitos y continuos se llaman árboles de regresión.
Un árbol de decisión se considera ideal cuando representa la mayor cantidad de datos con el menor número de niveles o preguntas. Los algoritmos diseñados para crear árboles de decisión optimizados incluyen CART (el más utilizado y el que estudiaremos en esta materia), ASSISTANT, CLS y ID3/4/5. Un árbol de decisión también se puede generar mediante la creación de reglas de asociación, ubicando la variable objetivo a la derecha.
Cada método debe determinar cuál es la mejor forma de dividir los datos en cada nivel. Los métodos comunes para hacerlo incluyen la medición de la impureza de Gini, la obtención de información y la reducción de variaciones.
Ventajas y desventajas
Emplear los árboles de decisión en el aprendizaje automático tiene numerosas ventajas:
El costo del uso del árbol para predecir los datos disminuye con cada punto de datos adicional.
Funciona para los datos numéricos o categóricos.
Puede modelar problemas con múltiples resultados.
Usa un modelo de caja blanca (lo que hace que los resultados sean fáciles de explicar). Los algoritmos caja blanca son aquellos que normalmente trabajan sobre funciones matemáticas o de lógica que el programador conoce muy bien y que va modificando para mejorar el rendimiento del algoritmo.
La fiabilidad de un árbol se puede cuantificar y poner a prueba.
Tiende a ser preciso independientemente de si viola las suposiciones de los datos de origen.
Pero también tienen algunas desventajas:
Cuando se presentan datos categóricos con múltiples niveles, la información obtenida se inclina a favor de los atributos con mayoría de niveles.
Los cálculos pueden volverse complejos al lidiar con la falta de certezas y numerosos resultados relacionados.
Las conjunciones entre nodos se limitan a AND, mientras que los gráficos de decisión admiten nódulos relacionados mediante OR.
Para tener en cuenta sobre árboles
Son un tipo de algoritmos de aprendizaje supervisado (es decir, existe una variable objetivo predefinida).
Principalmente usados en problemas de clasificación.
Las variables de entrada y salida pueden ser categóricas o continuas.
Divide el espacio de predictores (variables independientes) en regiones distintas y no sobrepuestas. Por ejemplo:
Se divide la población o muestra en conjuntos homogéneos basados en la variable de entrada más significativa.
La construcción del árbol sigue un enfoque de división binaria recursiva (top-down greddy approach). Greedy -> analiza la mejor variable para ramificación sólo en el proceso de división actual.
Ejemplo
Tenemos un conjunto de datos correspondiente a 30 estudiantes y 3 variables:
*Género (hombre/mujer),
*Clase (IX/X) y
*Altura (5 a 6 pies).
Sabemos que 15 estudiantes juegan cricket en su tiempo libre. Queremos crear un modelo para predecir quien jugará cricket. Segregar estudiantes basados en todos los valores de las 3 variables e identificar aquella variable que crea los conjuntos más homogéneos de estudiantes y que a su vez son heterogéneos entre ellos.
¿Qué variable es la más significativa para la mejor división de la población?
Terminología a la hora de modelar
*Nodo raíz: población completa o muestra
Ramificación
Nodo de decisión
Nodo terminal y hoja
*Poda
*Rama/sub-árbol
*Nodos padre e hijo
Árboles de regresión versus árboles de clasificación
El modelo de conjunto de árboles consta de un conjunto de árboles de clasificación y regresión (CART), el cual fue desarrollado por Breiman et al en 1984.
Ahora bien, ¿cuál es la diferencia entre árboles de clasificación y regresión?*
| Variable a predecir es continua |
Variable a predecir es categórica |
| Valores de los nodos terminales se reducen a la medida de las observaciones en esa región |
El valor en el nodo terminal se reduce a la moda de las observaciones del conjunto de entrenamiento que han llegado o caído en la región. |
En los árboles de decisión comenzamos por una pregunta. Aquí hay un ejemplo simple de un CART que clasifica si a alguien le gustará un hipotético juego de computadora X, dónde la pregunta es ¿Le gustan los juegos de computadora X?
Clasificamos a los integrantes de nuestro conjunto de datos en diferentes ramas según la edad y se la asigna una puntuación correspondiente en el vértice.
Un CART es un poco diferente de los árboles de decisión, en los que la hoja solo contiene valores de decisión. En CART, se asocia una puntuación real a cada una de las hojas, lo que nos da interpretaciones más ricas que van más allá de la clasificación. Esto también permite un enfoque unificado y basado en principios para la optimización.
Por lo general, un solo árbol no es lo suficientemente fuerte para usarse en la práctica. Lo que se utiliza realmente es el modelo de conjunto, que suma la predicción de varios árboles juntos.
A continuación,se muestra un ejemplo de un conjunto de dos árboles. Las puntuaciones de predicción de cada árbol individual se suman para obtener la puntuación final. Si miras el ejemplo, un dato importante es que los dos árboles intentan complementarse.
Matemáticamente, podemos escribir nuestro modelo en la forma \[
\hat{y}= \sum_{k=1}^K f_k(x_i), \space f_k \in \digamma
\] donde:
\(x_i\) es el individuo \(i\),
\(K\) es el número de árboles,
\(f\) es una función del espacio funcional \(\digamma\), y
\(\digamma\) es el conjunto de todos los CART posibles.
Se busca optimizar una función objetivo dada por:
\[
obj(\theta) = \sum_{i=1}^n l(y_i,\hat y_i)+\sum_{k=1}^K \varOmega (f_k)
\]
donde la primera parte representa la pérdida del entrenamiento y la segunda la regularización.
Aumento de árboles
Ya teniendo representado el modelo, pasamos al entrenamiento: ¿Cómo debe aprender los árboles? La respuesta es, como todos los modelos de aprendizaje supervisado: ¡defina una función objetivo y optimícela!
Sea la siguiente función objetivo (recuerde que siempre debe contener la pérdida de entrenamiento y la regularización):
\[
obj = \sum_{i=1}^n l(y_i,\hat y_i^{(t)})+\sum_{i=1}^t \varOmega (f_i)
\]
Entrenamiento aditivo
La primera pregunta que queremos hacernos: ¿cuáles son los parámetros de los árboles? Puede encontrar que lo que necesitamos que aprenda son esas funciones \(f_i\), cada uno con la estructura del árbol y puntuaciones en las hojas. Aprender la estructura del árbol es mucho más difícil que el problema de optimización tradicional en el que simplemente puede tomar el gradiente. Es difícil que se aprenda todos los árboles al mismo tiempo.
Por eso, se usa una estrategia aditiva: organizando lo que ha aprendido y agrega un árbol nuevo a la vez. Se va escribiendo el valor de predicción en el paso \(t\) como \(\hat y_i^{(t)}\) . Entonces se puede obtener:
\[
\begin{array}{l}
\hat y_i^{(0)}=0 \\
\hat y_i^{(1)}=f_1(x_i)=\hat y_i^{0}+f_1(x_i) \\
\hat y_i^{(2)}=f_1(x_i)+f_2(x_i)=\hat y_i^{1}+f2i(x_i)
\end{array}
\]
Entonces ahora nos falta ¿qué árbol queremos en cada paso? lo natural es sumar el que optimice la función objetivo
\[
\begin{align}
obj^{(t)} & = \sum_{i=1}^n l(y_i,\hat y_i^{(t)})+\sum_{i=1}^t \varOmega (f_i) \\
& = \sum_{i=1}^n l(y_i,\hat y_i^{(t-1)}+f_t(x_i))+ \varOmega (f_t) + \text{constant}
\end{align}
\] Si consideramos el uso del error cuadrático medio (MSE) como la función de pérdida, el objetivo se convierte en
\[
\begin{align}
obj^{(t)} & = \sum_{i=1}^n (y_i-(\hat y_i^{(t-1)}+f_t(x_i)))^2+\sum_{i=1}^t \varOmega (f_i) \\
& = \sum_{i=1}^n [2(\hat y_i^{(t-1)} - y_i)f_t(x_i)+f_t(x_i)^2]+ \varOmega (f_t) + \text{constant}
\end{align}
\] La forma de MSE es amigable, con un término de primer orden (generalmente llamado residual) y un término cuadrático. Para otras pérdidas de interés (por ejemplo, pérdida logística), no es tan fácil conseguir una forma tan bonita. Entonces, en el caso general, tomamos la expansión de Taylor de la función de pérdida hasta el segundo orden:
\[
obj^{(t)} = \sum_{i=1}^n [l(y_i,\hat y_i^{(t-1)})+g_if_t(x_i)+\frac{1}{2}h_if_t^2(x_i)] + \varOmega (f_t) + \text{constant}
\]
donde, \[
\begin{align}
g_i = \partial_{\hat{y}_i^{(t-1)}}l(y_i,\hat{y}_i^{t-1})\\
h_i = \partial^2_{\hat{y}_i^{(t-1)}}l(y_i,\hat{y}_i^{t-1})
\end{align}
\] Después de eliminar todas las constantes, el objetivo específico en el paso se convierte en
\[
\sum_{i=1}^n[g_if_t(x_i)+\frac{1}{2}h_if_t^2(x_i)]+\varOmega (f_t)
\]
Este se convierte en la función objetivo de optimización para el nuevo árbol. Una ventaja importante de esta definición es que el valor de la función objetivo solo depende de y \(g_i\) y \(h_i\). Así es como algoritmo como XGBoost admite funciones de pérdida personalizadas. Se puede optimizar cada función de pérdida, incluida la regresión logística y la clasificación por pares, utilizando exactamente el mismo solucionador que toma \(g_i\) y \(h_i\) como entrada!
La puntuación de estructura
Aquí está la parte mágica de la derivación. Después de reformular el modelo de árbol, podemos escribir el valor objetivo con el \(t\)-th árbol como:
\[
\begin{align}
obj^{(t)} & \approx \sum_{i=1}{n}[g_iw_{q(x_i)}+\frac{1}{2}h_iw^2_{q(x_i)}]+\gamma T+\frac{1}{2}\lambda \sum_{j=1}^Tw^2_j \\
& = \sum_{j=1}^T [(\sum_{i\in I_j}g_i)w_j+\frac{1}{2}(\sum_{i\in I_j}h_i+\lambda)w_j^2]+\gamma T
\end{align}
\]
donde, \(I_j= \{ i |q(x_i)=j\}\) es el conjunto de índices de puntos de datos asignados a la \(j\)-th hoja. Observe que en la segunda línea hemos se cambia el índice de la suma porque todos los puntos de datos en la misma hoja obtienen la misma puntuación. Podríamos comprimir aún más la expresión definiendo \(G_j = \sum_{i\in I_j}g_i\) y \(H_j = \sum_{i\in I_j}h_i\)
\[
obj^{(t)} = \sum_{j=1}^T [G_jw_j+\frac{1}{2}(H_j+\lambda)w_j^2]+\gamma T
\]
En esta ecuación, \(w_j\) son independientes entre sí, la forma \(G_jw_j+ \frac{1}{2}(H_j+\lambda)w_j^2\) es cuadrática, y por tanto podemos encontrar el mejor \(w_j\) para la estructura dada \(q(x)\) y podemos redur la función objetivo de la siguiente forma:
\[
\begin{align}
w_j^* &= -\frac{G_j}{H_j+\lambda} \\
obj^* &= - \frac{1}{2}\sum_{j=1}^T \frac{G_j^2}{H_j+\lambda}+\gamma T
\end{align}
\] La última ecuación mide qué tan buena estructura de árbol es \(q(x)\):
Todo esto suena un poco complicado, veamos cómo se pueden calcular las puntuaciones por medio de la imagen. Básicamente, para una estructura de árbol determinada, empujamos las estadísticas \(g_i\) y \(h_i\) a las hojas a las que pertenecen, sume las estadísticas y use la fórmula para calcular qué tan bueno es el árbol. Esta puntuación es como la medida de impurezas en un árbol de decisión, excepto que también toma en cuenta la complejidad del modelo.
Estructura del árbol
Luego de medir qué tan bueno es el árbol, lo ideal sería enumerar todos los árboles posibles y elegir el mejor. En la práctica sabemos que no debemos hacerlo por el coste computacional que implica.
Específicamente, tratemos de dividir una hoja en dos hojas, y la puntuación que se obtiene es
\[
Gain = \frac{1}{2} \left[ \frac{G^2_L}{H_L+\lambda}+\frac{G^2_R}{H_R+\lambda}- \frac{(G_L+G_R)^2}{H_L+H_R+\lambda} \right]-\gamma
\]
Esta fórmula se puede descomponer como:
la puntuación en la nueva hoja izquierda,
la puntuación en la nueva hoja derecha,
La puntuación en la hoja original, y
regularización en la hoja adicional.
Podemos ver un hecho importante aquí: si la ganancia es menor que \(\gamma\), sería mejor no agregar esa rama.
¡Estas son exactamente las técnicas de poda en modelos basados en árboles! Al utilizar los principios del aprendizaje supervisado, naturalmente podemos encontrar la razón por la que estas técnicas funcionan.
Para datos de valor real, generalmente queremos buscar una división óptima. Para hacerlo de manera eficiente, colocamos todas las instancias de forma ordenada, como en la siguiente imagen.
Un escaneo de izquierda a derecha es suficiente para calcular la puntuación de estructura de todas las posibles soluciones de división, y podemos encontrar la mejor división de manera eficiente.
Ventajas y desventajas respecto a otros algoritmos o modelos
Ventajas
Fácil de entender
Útil en exploración de datos: identificar importancia de variables a partir de cientos de variables.
Menos limpieza de datos: outliers y valores faltantes no influencian el modelo (A un cierto grado)
El tipo de datos no es una restricción
Es un método no paramétrico (i.e., no hay suposición acerca del espacio de distribución y la estructura del clasificador)
Desventajas
Sobreajuste
Pérdida de información al categorizar variables continuas
Precisión: métodos como SVM y clasificadores tipo ensamblador a menudo tienen tasas de error 30% más bajas que CART (Classification and Regression Trees)
Inestabilidad: un pequeño cambio en los datos puede modificar ampliamente la estructura del árbol. Por lo tanto la interpretación no es tan directa como parece.
¿Cómo decide un árbol dónde ramificarse?
La decisión de hacer divisiones estratégicas afecta altamente la precisión del árbol. Los criterios de decisión son diferentes para árboles de clasificación y regresión. Existen varios algoritmos para decidir la ramificación. La creación de subnodos incrementa la homogeneidad de los subnodos resultantes. Es decir, la pureza del nodo se incrementa respecto a la variable objetivo. Al final, se prueba la división con todas las variables y se escoge la que produce subnodos más homogéneos.
Algunos algoritmos más comunes para la selección:
Índice Gini
Este índice se basa en la expresión: “Si seleccionamos aleatoriamente dos ítems de una población, entonces estos deben ser de la misma clase y la probabilidad de esto es 1 si la población es pura”.
Algunas consideraciones:
Variable objetivo categórica: “Success” o “Failure”
Solo divisiones binarias
A mayor valor de índice Gini, mayor la homogeneidad
CART (Classification and Regression Tree) usa el método de Gini para la división binaria.
Para su cálculo::
Calcular Gini para los subnodos usando la fórmula de la suma de los cuadrados de probabilidad para success y failure \((p^2 + q^2)\).
Calcular Gini para la división usando score Gini ponderado para cada nodo de la división.
Para entender mejor todo esto, veamos un ejemplo:
| Mujer \(0.2^2+0.8^2=0.68\) |
IX \(0.43^2+0.57^2=0.51\) |
| Hombre \(0.65^2+0.35^2=0.55\) |
X \(0.56^2+0.44^2=0.51\) |
| Pond. \((10/30)0.68+(20/30)0.55 = 0.59\) |
Pond. \((14/30)0.51 + (16/30)0.51 = 0.51\) |
Chi cuadrado
Un algoritmo para encontrar la significancia estadística de las diferencias entre subnodos y un nodo padre. Se mide a partir de la suma de los cuadrados de las diferencias estandarizadas entre las frecuencias observadas y esperadas de la variable objetivo.
Algunas consideraciones:
Variable objetivo categórica “Success” o “Failure”.
Dos o más divisiones
A más alto valor de Chi-Cuadrado, más alta la significancia estadística de las diferencias entre cada nodo y el nodo padre.
Fórmula: \(\left[\frac{(Real-Esperado)^2}{Esperado} \right]^{\frac{1}{2}}\)
Para su cálculo:
Calcular Chi-Cuadrado para cada nodo individualmente a través de la desviación para ambos: Success y Failure
Calcular Chi-Cuadrado de la división usando la suma de todos los Chi-Cuadrado de Success y Failure de cada nodo en la división.
Continuando con el ejemplo anterior, pero teniendo las siguientes consideraciones:
Para el nodo “Mujer”. Los valores reales para “Play Cricket” y “Not Play Cricket” son 2 y 8, respectivamente.
Para calcular el valor esperado, asignaremos la misma probabilidad que su nodo padre (50%). Por lo tanto para ambos casos el valor sería 5 considerando el total de elementos “Mujer” (10).
Calcular las diferencias para usar en la fórmula, Real-Esperado. Para “Play Cricket” (2-5=-3) y para “No Play Cricket” (8-5=3)
Calcular Chi-Cuadrado del nodo para “Play Cricket” y “No Play Cricket” usando la fórmula completa \(\left[\frac{(Real-Esperado)^2}{Esperado} \right]^{\frac{1}{2}}\).
Seguir los pasos 1-4 para el caso del nodo “Hombre”.
finalmente sumar todos los Chi-Cuadrado para calcular el Chi-Cuadrado para la división de la variable Género.
| Female |
2 |
8 |
10 |
5 |
5 |
- 3 |
1.34 |
1.34 |
| Male |
13 |
7 |
20 |
10 |
10 |
3 |
0.95 |
0.95 |
Por lo tanto el total Chi cuadrado es 4.58.
Podemos hacer el mismo procedimiento para la variable “Class”:
| IX |
6 |
8 |
14 |
7 |
-1 |
1 |
0.38 |
0.38 |
| X |
9 |
7 |
16 |
8 |
1 |
-1 |
0.35 |
0.35 |
Por lo tanto el total Chi cuadrado es 1.46.
Reducción en la varianza (regresión)
Los algoritmos anteriores se aplicaban para problemas de clasificación con variables objetivo categórica. Por otra parte, la reducción en la varianza es un algoritmo usado para variables objetivo continuas (problemas de regresión). Este algoritmo usa la fórmula estándar de la varianza para escoger el criterio de división. La división con la varianza más baja se escoge para dividir la población:
\[
\text{Varianza}= \frac{\sum(X-\bar{X})^2}{n}
\]
Para su cálculo primero calculamos la varianza en cada nodo, para luego calcular la varianza de cada división por un promedio ponderado de las varianzas de los nodos.
Continuando con el ejemplo, asumiremos que vamos a convertir los valores numéricos de 1 para play cricket y cero para no play cricket.
| Nodo Padre |
(15x1 + 15x0)/30 = 0.5 |
(15x(1-0.5)^2 + 15x(0-0.5)^2) / 30 = 0.25 |
| Nodo Mujer |
(2x1 + 8x0)/10=0.2 |
(2x(1-0.2)^2 + 8x(0-0.2)^2) / 10 = 0.16 |
| Nodo Hombre |
(13x1 + 7x0)/20=0.65 |
(13x(1-0.65)^2 + 7*(0-0.65)^2) / 20 = 0.23 |
| Género ponderado |
|
(10/30)x0.16 + (20/30) *0.23 = 0.21 |
| Nodo Clase IX |
(6x1 + 8x0)/14=0.43 |
(6x(1-0.43)^2 + 8x(0-0.43)^2) / 14= 0.24 |
| Nodo Clase X |
(9x1 + 7x0)/16=0.56 |
(9x(1-0.56)^2 + 7x(0-0.56)^2) / 16 = 0.25 |
| Clase ponderado |
|
(14/30)x0.24 + (16/30) x0.25 = 0.25 |
Parámetros del modelo y como evitar sobreajuste en árboles de decisión
El sobreajuste es uno de los desafíos más importantes en el proceso de modelación de árboles de decisión. Si no se definen límites, el árbol tendrá un 100% de precisión en el conjunto de datos de entrenamiento. En el peor caso tendrá una hoja por cada observación.
Dos formas de evitar el sobreajuste: (a) Definir restricciones sobre el tamaño del árbol y (b) Podar el árbol.
Definir restricciones sobre el tamaño del árbol (prepruning)
Uso de parámetros para definir un árbol. Los parámetros son independientes de la herramienta de programación (R & Python)
- Mínimo de observaciones para dividir un nodo
Mínimo número de muestras u observaciones que se requieren en un nodo para ser considerado para ramificación.
Valores más altos previenen que el modelo aprenda relaciones muy específicas.
Valores demasiado altos pueden causar un pobre ajuste del modelo. El parámetro debe ajustarse usando validación cruzada.
- Mínimo número de observaciones para un nodo terminal
- Valores más bajos son necesarios para problemas de clases no balanceadas.
- Máxima profundidad del árbol (vertical)
- Máximo número de nodos hoja
- Se puede definir en lugar de máxima profundidad. Profundidad n = máximo 2^n hojas
- Máximo número de atributos a considerar para la ramificación
Seleccionados aleatoriamente.
Como regla general, la raíz cuadrada del número total de atributos funciona apropiadamente. Sin embargo, se debe probar hasta un 30%-40% del número total de atributos.
Poda del árbol (postpruning)
Su implementación es sencilla.
Construir el árbol a un profundidad extensa.
Remover las hojas que den un valor negativo comparado desde la raíz. Existen varios criterios que pueden ser utilizados, algunos basados en heurísticas y otros en parámetros de regularización (penalización).
Ejemplo: Supongamos que un nodo de decisión da una ganancia de -10 (pérdida de 10) y la siguiente ramificación da una ganancia de 20. Un árbol de decisión simple pararía en el paso uno, sin embargo, el proceso de poda considerará la ganancia general de +10 y mantendrá ambas hojas.
Librerías: El clasificador de árbol de decisión en la libraría de python Scikit actualmente no soporta el proceso de poda. Paquetes avanzados como xgboost lo incoporan. Por otra parte, el paquete de R rpart provee una función de poda directamente.
LS0tCnRpdGxlOiAiQmxvcXVlIDI6IEZ1bmRhbWVudG9zIGRlIGxhIGNvbnN0cnVjY2nDs24gZGUgw6FyYm9sZXMgZGUgZGVjaXNpw7NuIgpzdWJ0aXRsZTogIkFuYWzDrXRpY2EgYmFzYWRhIGVuIMOhcmJvbGVzIGRlIGNsYXNpZmljYWNpw7NuIHkgcmVncmVzacOzbiIKYXV0aG9yOiAiUHJvZmVzb3JhOiBEcmEuIERpYW5hIFBhb2xhIE1vbnRveWEgRXNjb2JhciBkaWFuYS5tb250b3lhQGl0ZXNvLm14IgpkYXRlOiAiRmVicmVybyAyMDIyIgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogeWVzCiAgICB0b2NfZmxvYXQ6IHllcwogICAgdGhlbWU6IGNvc21vCiAgICBoaWdobGlnaHQ6IHRhbmdvCiAgZ2l0aHViX2RvY3VtZW50OgogICAgdG9jOiB5ZXMKICAgIGRldjoganBlZwotLS0KYGBge3Igc2V0dXAsIGVjaG8gPSBGQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG89IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICBmaWcuaGVpZ2h0ID0gNiwgZmlnLndpZHRoID0gNykKYGBgCgo8c3R5bGU+Ci5mb3JjZUJyZWFrIHsgLXdlYmtpdC1jb2x1bW4tYnJlYWstYWZ0ZXI6IGFsd2F5czsgYnJlYWstYWZ0ZXI6IGNvbHVtbjsgfQo8L3N0eWxlPgoKPGNlbnRlcj4KIVtdKC4vaW1hZ2VzL2RyeV90cmVlLnBuZyl7d2lkdGg9MTAlfQohW10oLi9pbWFnZXMvaXRlc28uanBlZyl7d2lkdGg9NSV9CjwvY2VudGVyPgoKIyDCv1F1w6kgZXMgdW4gw6FyYm9sIGRlIGRlY2lzacOzbj8KClVuICrDoXJib2wgZGUgZGVjaXNpw7NuKiBlcyB1biBtYXBhIGRlIHBvc2libGVzIHJlc3VsdGFkb3MgZW4gdW5hIHNlcmllIGRlIGRlY2lzaW9uZXMgcmVsYWNpb25hZGFzLiAgVW4gZGlhZ3JhbWEgcXVlIG11ZXN0cmEgKmxhIHByb2JhYmlsaWRhZCBlc3RhZMOtc3RpY2EqIG8gZGV0ZXJtaW5hIHVuIGN1cnNvIGRlIHVuYSBhY2Npw7NuLiAgTXVlc3RyYSBhIGxvcyBhbmFsaXN0YXMgeSwgYSBsb3MgcXVlICp0b21hbiBsYXMgZGVjaXNpb25lcyosIHF1w6kgcGFzb3MgZGViZW4gdG9tYXIgeSBjw7NtbyBsYXMgZGlmZXJlbnRlcyBlbGVjY2lvbmVzIHBvZHLDrWFuIGFmZWN0YXIgdG9kbyBlbCBwcm9jZXNvLiBUb2RvIGVsbG8gc29wb3J0YWRvIGVuICpkYXRvcyouCgpMb3Mgw6FyYm9sZXMgZGUgZGVjaXNpw7NuIGNvbWllbnphbiBjb24gdW4gKipub2RvKiosIGRlbCBjdWFsIHNhbGVuIG90cm9zIGVuIGZ1bmNpw7NuIGRlIGxhcyBvcGNpb25lcyBxdWUgc2UgcHJlc2VudGVuLCB5IGRlIGNhZGEgdW5hIGRlIGVzdGFzLCBvdHJvcy4gRXhpc3RlbiB0cmVzIHRpcG9zIGRpZmVyZW50ZXMgZGUgbm9kb3M6CgoqICoqTm9kb3MgZGUgZGVjaXNpw7NuOioqIFNlIGxlIHJlcHJlc2VudGEgY29uIHVuIGN1YWRyYWRvIHkgbXVlc3RyYSB1bmEgZGVjaXNpw7NuIHF1ZSBzZSB0b21hcsOhLgoKKiAqKk5vZG9zIGRlIHByb2JhYmlsaWRhZDoqKiBFc3TDoSByZXByZXNlbnRhZG8gcG9yIHVuIGPDrXJjdWxvIHkgbXVlc3RyYSBsYXMgcHJvYmFiaWxpZGFkZXMgZGUgY2llcnRvcyByZXN1bHRhZG9zLgogCiogKipOb2RvcyB0ZXJtaW5hbGVzOioqIFNvbiBkZSBmb3JtYSB0cmlhbmd1bGFyLCB5IG11ZXN0cmEgZWwgcmVzdWx0YWRvIGRlZmluaXRpdm8gZGUgdW5hIHJ1dGEgZGUgZGVjaXNpw7NuLgoKT3Ryb3MgY29uY2VwdG9zIGltcG9ydGFudGVzOgoKKk90cm8gY29uY2VwdG8gaW1wb3J0YW50ZSBhIHRlbmVyIGVuIGN1ZW50YSBzb24gbGFzCgoqICoqUmFtaWZpY2FjaW9uZXMqKi4gRXN0YXMgc2UgcmVwcmVzZW50YW4gcG9yIGzDrW5lYXMgZW50cmUgbG9zIG5vZG9zIGUgaW5kaWNhbiB1biBwb3NpYmxlIHJlc3VsdGFkbyBvIGFjY2nDs24gZGVudHJvIGRlbCDDoXJib2wuCgoqICoqSG9qYXM6KiogTGFzIGhvamFzIHNvbiBsYXMgdGVybWluYWNpb25lcyBkZSB0b2RhcyBsYXMgcmFtYXMgKGVsIG7Dum1lcm8gZGUgdHJpw6FuZ3Vsb3MgbyBub2RvcyB0ZXJtaW5hbGVzKQoKCiMjIMK/Q8OzbW8gaGFjZW1vcyB1biDDoXJib2wgZGUgZGVjaXNpw7NuPwoKUGFyYSByZWFsaXphciB1biDDoXJib2wgZGUgZGVjaXNpw7NuLCBwb2RlbW9zIHNlZ3VpciBsb3Mgc2lndWllbnRlcyBwYXNvczoKCjEuICAqKkNvbWVuemFtb3MgY29uIGxhIGRlY2lzacOzbiBwcmluY2lwYWw6KiogQ29tZW56YXJlbW9zIGRpYnVqYW5kbyB1biBjdWFkcm8gcXVlIHNlcsOhIGVsICpub2RvIHByaW5jaXBhbCouICBMdWVnbywgaGFjaWEgbGEgZGVyZWNoYSBjb21lbnphbW9zIGEgaGFjZXIgbGFzICpyYW1pZmljYWNpb25lcyosIHF1ZSByZXByZXNlbnRhbiBsYXMgcG9zaWJsZXMgZGVjaXNpb25lcyB5IGxhcyBldGlxdWV0YW1vcy4KCjIuICoqQWdyZWdhbW9zIGEgY2FkYSByYW1pZmljYWNpw7NuIG5vZG9zIGRlIGRlY2lzacOzbiB5IHByb2JhYmlsaWRhZDoqKiBlc3RvIGhhY2UgcXVlIHNlIGV4cGFuZGEgZWwgw6FyYm9sIGRlbCBzaWd1aWVudGUgbW9kbzoKCiogU2kgb3RyYSBkZWNpc2nDs24gZXMgbmVjZXNhcmlhLCBlbnRvbmNlcyBjb2xvY2Ftb3MgdW4gY3VhZHJvIHF1ZSByZXByZXNlbnRhIHVuIG5vZG8gZGUgZGVjaXNpw7NuLgoKKiBTaSBlbCByZXN1bHRhZG8gZXMgaW5jaWVydG8sIGRpYnVqYW1vcyB1biBjw61yY3VsbyAocXVlIHJlcHJlc2VudGEgIGxvcyBub2RvcyBkZSBwcm9iYWJpbGlkYWQpLCBjdWFuZG8gdGVuZW1vcyB1biBldmVudG8gZW4gZWwgY3VhbCBjb25vY2Vtb3MgbGEgcHJvYmFiaWxpZGFkLgoKKiBTaSBlbCBwcm9ibGVtYSBwb3IgbWVkaW8gZGUgZXNhIHJhbWlmaWNhY2nDs24geWEgZmluYWxpemEgcG9uZW1vcyB1biB0cmnDoW5ndWxvCgpEZXNkZSBjYWRhIG5vZG8gZGUgZGVjaXNpw7NuLCBkaWJ1amEgc29sdWNpb25lcyBwb3NpYmxlcyBjb24gcmFtaWZpY2FjaW9uZXMuIERlc2RlIGNhZGEgbm9kbyBkZSBwcm9iYWJpbGlkYWQsIGRpYnVqYSBsw61uZWFzIHF1ZSByZXByZXNlbnRlbiBsb3MgcmVzdWx0YWRvcyBwb3NpYmxlcy4gU2kgZGVzZWFzIGFuYWxpemFyIHR1cyBvcGNpb25lcyBkZSBmb3JtYSBudW3DqXJpY2EsIGluY2x1eWUgbGEgcHJvYmFiaWxpZGFkIGRlIGNhZGEgcmVzdWx0YWRvIHkgZWwgY29zdG8gZGUgY2FkYSBhY2Npw7NuLgoKMy4gKipDb250aW7DumEgY29uIGxhIGV4cGFuc2nDs24gaGFzdGEgcXVlIGNhZGEgbMOtbmVhIGFsY2FuY2UgdW4gZXh0cmVtbyoqLCBsbyBxdWUgc2lnbmlmaWNhIHF1ZSBubyBoYXkgbcOhcyBkZWNpc2lvbmVzIHF1ZSB0b21hciBvIHJlc3VsdGFkb3MgcHJvYmFibGVzIHF1ZSBjb25zaWRlcmFyLiBMdWVnbywgYXNpZ25hIHVuIHZhbG9yIGEgY2FkYSByZXN1bHRhZG8gcG9zaWJsZS4gUHVlZGUgc2VyIHVuYSBwdW50dWFjacOzbiBhYnN0cmFjdGEgbyB1biB2YWxvciBmaW5hbmNpZXJvLiBBZ3JlZ2EgdHJpw6FuZ3Vsb3MgcGFyYSBpbmRpY2FyIGxvcyBleHRyZW1vcy4KCioqKkNvbiB1biDDoXJib2wgZGUgZGVjaXNpw7NuIGNvbXBsZXRvLCB5YSBlc3TDoXMgbGlzdG8gcGFyYSBjb21lbnphciBhIGFuYWxpemFyIGxhIGRlY2lzacOzbiBxdWUgZW5mcmVudGFzLioqKgoKIyMgVmVudGFqYXMgeSBkZXN2ZW50YWphcwoKTG9zIMOhcmJvbGVzIGRlIGRlY2lzacOzbiBzaWd1ZW4gc2llbmRvIHBvcHVsYXJlcyBwb3IgcmF6b25lcyBjb21vIGxhcyBzaWd1aWVudGVzOgoKKiBTb24gbXV5IGbDoWNpbGVzIGRlIGVudGVuZGVyCgoqIFB1ZWRlbiBzZXIgw7p0aWxlcyBjb24gbyBzaW4gZGF0b3MgZmVoYWNpZW50ZXMsIHkgY3VhbHF1aWVyIGRhdG8gcmVxdWllcmUgdW5hIHByZXBhcmFjacOzbiBtw61uaW1hCgoqIFNlIHB1ZWRlbiBhZ3JlZ2FyIG51ZXZhcyBvcGNpb25lcyBhIGxvcyDDoXJib2xlcyBleGlzdGVudGVzCgoqIFN1IHZhbG9yIGFsIHNlbGVjY2lvbmFyIGxhIG1lam9yIGRlIG51bWVyb3NhcyBvcGNpb25lcwoKKiBTZSBjb21iaW5hbiBmw6FjaWxtZW50ZSBjb24gb3RyYXMgaGVycmFtaWVudGFzIGRlIHRvbWEgZGUgZGVjaXNpb25lcwoKKiAqUG9kZW1vcyBlbmNvbnRyYXIgdW4gdmFsb3IgZXNwZXJhZG8geSBvcHRpbWl6YXJsbyBwYXJhIGVuY29udHJhciBsYSBtZWpvciBkZWNpc2nDs24qLgoKU2luIGVtYmFyZ28sIGxvcyDDoXJib2xlcyBkZSBkZWNpc2nDs24gcHVlZGVuIHZvbHZlcnNlIGV4Y2VzaXZhbWVudGUgY29tcGxlam9zLiBFbiBlc29zIGNhc29zLCB1biBkaWFncmFtYSBkZSBpbmZsdWVuY2lhIG3DoXMgY29tcGFjdG8gcHVlZGUgc2VyIHVuYSBidWVuYSBhbHRlcm5hdGl2YS4gTG9zIGRpYWdyYW1hcyBkZSBpbmZsdWVuY2lhIHNlIGVuZm9jYW4gZW4gbG9zIG9iamV0aXZvcywgbGFzIGVudHJhZGFzIHkgbGFzIGRlY2lzaW9uZXMgZnVuZGFtZW50YWxlcy4KCgojIyBFamVtcGxvIGRlIMOhcmJvbCBkZSBjcmVhY2nDs24gZGVjaXNpw7NuICpQZXRybyBFbnRlcnByaXNlcyoKClBhcmEgZW50ZW5kZXIgbGEgY29uc3RydWNjacOzbiBkZSB1biDDoXJib2wgaGFnYW1vcyB1biBlamVtcGxvOgoKKlBldHJvIEVudGVycHJpc2VzKiBlcyB1bmEgY29tcGHDscOtYSBkZSBwZXRyw7NsZW9zIGRlIFRleGFzLiBMYSBjb21wYcOxw61hIFBldHJvIHRpZW5lIHVuYSBvcGNpw7NuIGludHJhbnNmZXJpYmxlIGEgY29ydG8gcGxhem8gcGFyYSBwZXJmb3JhciBlbiB1bmEgZGV0ZXJtaW5hZGEgcGFyY2VsYSBkZSB0aWVycmEuIExhIG9wY2nDs24gZXMgZWwgw7puaWNvIGFjdWVyZG8gY29tZXJjaWFsIGVuIGVsIHF1ZSBsYSBlbXByZXNhIGVzdMOhIGludm9sdWNyYWRhIGFob3JhIG8gcXVlIGVzcGVyYXIgY29uc2lkZXJhciBlbnRyZSBhaG9yYSB5IGVsIDMxIGRlIGRpY2llbWJyZSBkZSAxOTY3LCBtb21lbnRvIGVuIGVsIHF1ZSBzZSB0ZXJtaW5hcsOtYSBsYSBwZXJmb3JhY2nDs24gc2kgc2UgZWplcmNpZXJhIGxhIG9wY2nDs24uCgpEb3MgcmVjaWVudGVzIHBlcmZvcmFjaW9uZXMgZW4gc2VjbyBlbiBvdHJvcyBsdWdhcmVzIGhhbiByZWR1Y2lkbyBsb3MgYWN0aXZvcyBsw61xdWlkb3MgbmV0b3MgZGUgbGEgY29tcGHDscOtYSBQZXRybyBhIDEzMC4wMDAgZMOzbGFyZXMsIHkgV2lsbGlhbSBTbnlkZXIsIHByZXNpZGVudGUgeSBwcmluY2lwYWwgYWNjaW9uaXN0YSwgZGViZSBkZWNpZGlyIHNpIFBldHJvIGRlYmUgZWplcmNlciBzdSBvcGNpw7NuIG8gZGVqYXJsYSBleHBpcmFyLiBMYSBvcGNpw7NuIGV4cGlyYXLDoSBkZW50cm8gZGUgZG9zIHNlbWFuYXMgc2kgbm8gc2UgaW5pY2lhIGxhIHBlcmZvcmFjacOzbiBwYXJhIGVudG9uY2VzLiAKClNueWRlciB0aWVuZSB0cmVzIG9wY2lvbmVzIHBvc2libGVzOgoKMS4gUGVyZm9yYXIgaW5tZWRpYXRhbWVudGUKCjIuIFBhZ2FyIHBhcmEgcXVlIHNlIHJlYWxpY2UgdW5hIHBydWViYSBzw61zbWljYSBlbiBsb3MgcHLDs3hpbW9zIGTDrWFzLCB5IGx1ZWdvLCBlbiBmdW5jacOzbiBkZWwgcmVzdWx0YWRvIGRlIGxhIHBydWViYSwgZGVjaWRpciBzaSBzZSBwZXJmb3JhIG8gbm8uCgozLiBEZWphciBxdWUgbGEgb3BjacOzbiBleHBpcmUKClVuYSB2ZXogZGVzY3JpdGFzIGxhcyBwb3NpYmxlcyBvcGNpb25lcyBkZSBTbnlkZXIsIHRhbWJpw6luIGRlYmVtb3MgY29ub2NlciBhbGdvIHNvYnJlIHN1cyBwb3NpYmxlcyBjb25zZWN1ZW5jaWFzIGVjb27Ds21pY2FzLiBQYXJhIGNvbnNlcnZhciBlbCBjYXBpdGFsIHkgbWFudGVuZXIgbGEgZmxleGliaWxpZGFkLCBQZXRybyBzdWJjb250cmF0YSB0b2RhcyBsYXMgcGVyZm9yYWNpb25lcyB5IHBydWViYXMgc8Otc21pY2FzOyBhZGVtw6FzLCB2ZW5kZSBpbm1lZGlhdGFtZW50ZSBsb3MgZGVyZWNob3MgZGUgY3VhbHF1aWVyIHBldHLDs2xlbyBkZXNjdWJpZXJ0bywgZW4gbHVnYXIgZGUgZGVzYXJyb2xsYXIgbG9zIGNhbXBvcyBwZXRyb2zDrWZlcm9zIHBvciBzw60gbWlzbWEuIFB1ZWRlIGhhY2VyIHF1ZSBsYSBwcnVlYmEgc8Otc21pY2Egc2UgbGxldmUgYSBjYWJvIGNvbiBwb2NhIGFudGVsYWNpw7NuIHkgY29uIHRhcmlmYXMgZGUgaG9yYXMgZXh0cmFzIHBvciB1bmEgdGFyaWZhIGZpamEgZGUgMzAuMDAwIGTDs2xhcmVzLCB5IGVsIHBvem8gcHVlZGUgcGVyZm9yYXJzZSBwb3IgdW5hIHRhcmlmYSBmaWphIGRlIDEwMC4wMDAgZMOzbGFyZXMuIFVuYSBncmFuIGNvbXBhw7HDrWEgcGV0cm9sZXJhIGhhIHByb21ldGlkbyBxdWUgc2kgUGV0cm8gcGVyZm9yYSB5IGRlc2N1YnJlIHBldHLDs2xlbywgY29tcHJhcsOhIHRvZG9zIGxvcyBkZXJlY2hvcyBkZSBQZXRybyBwb3IgdW4gcHJlY2lvIGZpam8gZGUgNDAwLjAwMCBkw7NsYXJlcy4KClBhcmEgY29tcGxldGFyIGxhIGRlc2NyaXBjacOzbiwgZXMgbmVjZXNhcmlvIGNvbm9jZXIgbGFzIHByb2JhYmlsaWRhZGVzIGFzaWduYWRhcyBhIGxhcyBkaXN0aW50YXMgY29udGluZ2VuY2lhcy4gRWwgZ2XDs2xvZ28gZGUgbGEgZW1wcmVzYSBoYSBleGFtaW5hZG8gbGEgZ2VvbG9nw61hIGRlIGxhIHJlZ2nDs24geSBhZmlybWEgcXVlIGV4aXN0ZSB1bmEgcHJvYmFiaWxpZGFkIGRlIDAsNTUgZGUgcXVlLCBzaSBzZSBodW5kZSB1biBwb3pvLCBzZSBkZXNjdWJyYSBwZXRyw7NsZW8uIExvcyBkYXRvcyBzb2JyZSBsYSBmaWFiaWxpZGFkIGRlIGxhIHBydWViYSBzw61zbWljYSBpbmRpY2FuIHF1ZSBzaSBlbCByZXN1bHRhZG8gZGUgbGEgcHJ1ZWJhIGVzIGZhdm9yYWJsZSwgbGEgcHJvYmFiaWxpZGFkIGRlIGVuY29udHJhciBwZXRyw7NsZW8gYXVtZW50YXLDoSBhIDAsODU7IHBlcm8gc2kgZWwgcmVzdWx0YWRvIGRlIGxhIHBydWViYSBlcyBkZXNmYXZvcmFibGUsIGJhamFyw6EgYSAwLDEwLiBFbCBnZcOzbG9nbyBoYSBjYWxjdWxhZG8gcXVlIGhheSB1bmEgcHJvYmFiaWxpZGFkIGRlIDAsNjAgZGUgcXVlIGVsIHJlc3VsdGFkbyBzZWEgZmF2b3JhYmxlIHNpIHNlIGhhY2UgbGEgcHJ1ZWJhLiBFeGlzdGUgdW5hIHNlbmNpbGxhLCBwZXJvIGltcG9ydGFudGUsIGludGVycmVsYWNpw7NuIGzDs2dpY2EgZW50cmUgZXN0YXMgcHJvYmFiaWxpZGFkZXMsIHNpIHF1aWVyZXMgY29ub2NlciBtw6FzIGFjZXJjYSBkZSBlbGxvIHB1ZWRlcyB2ZXJsbyBlbiBsYSByZWZlcmVuY2lhOiAqU2NobGFpZmVyLCBBbmFseXNpcyBvZiBEZWNpc2lvbnMgVW5kZXIgVW5jZXJ0YWludHksIG9wLiBjaXQsIENoYXB0ZXIgOSouCgpFc3RlIHByb2JsZW1hIGRlIGRlY2lzacOzbiBxdWUgaW1wbGljYSBpbmNlcnRpZHVtYnJlIHB1ZWRlIGVzdHJ1Y3R1cmFyc2UgZW4gZm9ybWEgZGVsIMOhcmJvbCBkZSBkZWNpc2nDs24gcXVlIHNlIG11ZXN0cmEgYSBjb250aW51YWNpw7NuLiBFbCDDoXJib2wgbXVlc3RyYSBsYXMgcHJvYmFiaWxpZGFkZXMsIGJhc2FkYXMgZW4gZWwganVpY2lvIGRlbCBnZcOzbG9nbyBkZSBsYSBlbXByZXNhLCBkZSBsb3MgZGlzdGludG9zIGV2ZW50b3MuCgo8Y2VudGVyPgohW10oLi9pbWFnZXMvcGV0cm9EVC5wbmcpCjwvY2VudGVyPgoKUG9kZW1vcyB2ZXIgcXVlIGNvbiBsYXMgY29uc2VjdWVuY2lhcyB5IGxhcyBwcm9iYWJpbGlkYWRlcyBwb2RlbW9zIGlyIGNvbnN0cnV5ZW5kbyB1biDDoXJib2wgZGUgZGVjaXNpw7NuIHBhcmEgZXN0YSBjb21wYcOxw61hLiAKCiMjIEVqZXJjaWNpbwoKU29tb3MgdHJhYmFqYWRvcmVzIGRlIHVuIGJhbmNvIGVuY2FyZ2Fkb3MgZGUgbGEgY29icmFuemEuIFF1ZXJlbW9zICp0b21hciBsYSBkZXRlcm1pbmFjacOzbiBzaSBsbGFtYXIgbyBubyBsbGFtYXIgYSBsb3MgY2xpZW50ZXMgZW4gbG9zIDUgeS9vIDEwIGTDrWFzIGRlIGFkZXVkb3MqLiAKClRlbmVtb3MgYWxndW5hIGluZm9ybWFjacOzbiBpbXBvcnRhbnRlLiAgUG9yIG1lZGlvIGRlIHVuIG1vZGVsbyBkZSByaWVzZ29zLCBoZW1vcyBkZXRlcm1pbmFkbyBsYSBwcm9iYWJpbGlkYWQgZGUgcGFnbyBkZSBsb3MgY2xpZW50ZXMgZGV0ZXJtaW5hZGEgeSBsYSBsbGFtYXJlbW9zICRwJC4gQSBjYXNhIGNsaWVudGUgc2UgbGUgcHJlc3TDsyB1bmEgY2FudGlkYWQgZGUgZGluZXJvICRCJC4gIAoKTm9zb3Ryb3MgcG9kZW1vcyB0b21hciBsYSBkZWNpc2nDs24gc2kgdXRpbGl6YW1vcyBhIG51ZXN0cm9zICpjbGllbnQgcGFydG5lcnMqIHBhcmEgcXVlIHNlIGNvbXVuaXF1ZW4gY29uIGxhcyBwZXJzb25hcyBvIG5vLCBwZXJvIGRlYmVtb3MgZGUgY29uc2lkZXJhciBxdWUgbGEgbGxhbWFkYSBub3MgY3Vlc3RhICQ4LiBBZGVtw6FzLCBzaSBlbCBjbGllbnRlIG5vIHBhZ2EgKHNlYSBxdWUgc2UgbGUgbGxhbWUgbyBxdWUgbm8gc2UgbGUgbGxhbWUpLCBsbyBtYW5kYW1vcyBhIHVuYSBhZ2VuY2lhIGV4dGVybmEgeSBzb2xvIHJlY2liaW1vcyBlbCA4MCUgZGVsIHRvdGFsIGRlbCBwcsOpc3RhbW8uCgoqKipEaXNjdXRlIGNvbiB0dXMgY29tcGHDsWVyb3MgZWwgcHJvYmxlbWEgeSByZWFsaXphIHVuIMOhcmJvbCBkZSBkZWNpc2lvbmVzIHBhcmEgcG9kZXIgdG9tYXIgbGEgbWVqb3IgZGVjaXNpw7NuLioqKgoKX19fX18KCiMgTG9zIMOhcmJvbGVzIGRlIGRlY2lzacOzbiBlbiBtaW5lcsOtYSBkZSBkYXRvcyB5IG1hY2hpbmUgbGVhcm5pbmcKClJlY29yZGVtb3MgcXVlLCBxdWl6w6FzIGxhIGlkZWEgZ2VuZXJhbCBxdWUgbXVjaGFzIHBlcnNvbmFzIHRpZW5lbiBzb2JyZSBtYWNoaW5lIGxlYXJuaW5n4oCmCgo8Y2VudGVyPgohW10oLi9pbWFnZXMvbWVtZU1MLnBuZykKPC9jZW50ZXI+CgpMbyBxdWUgZXMgZW4gcmVhbGlkYWTigKYKPGNlbnRlcj4KIVtdKC4vaW1hZ2VzL0FJLnBuZykKPC9jZW50ZXI+CgpDb21vIHlhIGhlbW9zIHZpc3RvIGNvbiBsYSBheXVkYSBkZSBgdGlkeW1vZGVsc2AgeSBgaDJvYCwgdW4gw6FyYm9sIGRlIGRlY2lzacOzbiB0YW1iacOpbiBwdWVkZSB1c2Fyc2UgcGFyYSBheXVkYXIgYSBjcmVhciBtb2RlbG9zIHByZWRpY3Rpdm9zIGF1dG9tw6F0aWNvcywgcXVlIHB1ZWRlbiBlbnRyZW5hcnNlIG1lZGlhbnRlIGFwcmVuZGl6YWplIGF1dG9tw6F0aWNvLCBlbiBtaW5lcsOtYSBkZSBkYXRvcyB5IGVzdGFkw61zdGljYS4gQ29ub2NpZG8gY29tbyAqbGVuZ3VhamUgYmFzYWRvIGVuIMOhcmJvbGVzIGRlIGRlY2lzacOzbiosIGVzdG9zIG3DqXRvZG9zIHRvbWFuIGVuIGNvbnNpZGVyYWNpw7NuIGxhcyBvYnNlcnZhY2lvbmVzIHNvYnJlIHVuIGVsZW1lbnRvIHBhcmEgcHJlZGVjaXIgdW4gdmFsb3IuCgpFbiBlc3RvcyDDoXJib2xlcyBkZSBkZWNpc2nDs24sICpsb3Mgbm9kb3MgcmVwcmVzZW50YW4gZGF0b3MgZW4gbHVnYXIgZGUgZGVjaXNpb25lcyouIEVzdGUgdGlwbyBkZSDDoXJib2wgdGFtYmnDqW4gc2UgY29ub2NlIGNvbW8gKsOhcmJvbCBkZSBjbGFzaWZpY2FjacOzbiouIENhZGEgcmFtaWZpY2FjacOzbiBjb250aWVuZSB1biBjb25qdW50byBkZSBhdHJpYnV0b3MgbyByZWdsYXMgZGUgY2xhc2lmaWNhY2nDs24gYXNvY2lhZGFzIGEgdW5hIGV0aXF1ZXRhIGRlIGNsYXNlIGVzcGVjw61maWNhLCBxdWUgc2UgaGFsbGEgYWwgZmluYWwgZGUgbGEgcmFtaWZpY2FjacOzbi4KCkVzdGFzIHJlZ2xhcywgdGFtYmnDqW4gY29ub2NpZGFzIGNvbW8gKnJlZ2xhcyBkZSBkZWNpc2nDs24qLCBzZSBwdWVkZW4gZXhwcmVzYXIgZW4gdW5hIGNsw6F1c3VsYSAqIlNpLi4uIGVudG9uY2VzLi4uIiouIENhZGEgdmFsb3IgZGUgZGF0b3MgbyBkZWNpc2nDs24gZm9ybWEgdW5hIGNsw6F1c3VsYSwgZGUgdGFsIGZvcm1hIHF1ZSwgcG9yIGVqZW1wbG8sICoic2kgbGFzIGNvbmRpY2lvbmVzIGAxYCwgYDJgIHkgYDNgIHNlIGN1bXBsZW4sIGVudG9uY2VzIGVsIHJlc3VsdGFkbyBgWGAgc2Vyw6EgZWwgcmVzdWx0YWRvIGRlZmluaXRpdm8gY29uIGNlcnRlemEgYFlgIiouCgpDYWRhIGRhdG8gYWRpY2lvbmFsIGF5dWRhIGEgcXVlIGVsIG1vZGVsbyBwcmVkaWdhIGRlIGZvcm1hIG3DoXMgcHJlY2lzYSBhIHF1w6kgY29uanVudG8gZmluaXRvIGRlIHZhbG9yZXMgcGVydGVuZWNlIGVsIGFzdW50byBlbiBjdWVzdGnDs24uIEVzYSBpbmZvcm1hY2nDs24gc2UgcHVlZGUgdXNhciBwb3N0ZXJpb3JtZW50ZSBjb21vIHVuYSBlbnRyYWRhIGVuIHVuIG1vZGVsbyBtw6FzIGdyYW5kZSBkZSB0b21hIGRlIGRlY2lzaW9uZXMuCgpBIHZlY2VzIGxhIHZhcmlhYmxlIHByZWRpY2hhIHNlcsOhIHVuIG7Dum1lcm8gcmVhbCwgY29tbyB1biBwcmVjaW8uIExvcyDDoXJib2xlcyBkZSBkZWNpc2nDs24gY29uIHJlc3VsdGFkb3MgcG9zaWJsZXMsIGluZmluaXRvcyB5IGNvbnRpbnVvcyBzZSBsbGFtYW4gKsOhcmJvbGVzIGRlIHJlZ3Jlc2nDs24qLgoKVW4gw6FyYm9sIGRlIGRlY2lzacOzbiBzZSBjb25zaWRlcmEgaWRlYWwgY3VhbmRvIHJlcHJlc2VudGEgbGEgbWF5b3IgY2FudGlkYWQgZGUgZGF0b3MgY29uIGVsIG1lbm9yIG7Dum1lcm8gZGUgbml2ZWxlcyBvIHByZWd1bnRhcy4gTG9zIGFsZ29yaXRtb3MgZGlzZcOxYWRvcyBwYXJhIGNyZWFyIMOhcmJvbGVzIGRlIGRlY2lzacOzbiBvcHRpbWl6YWRvcyBpbmNsdXllbiAqKipDQVJUKioqIChlbCBtw6FzIHV0aWxpemFkbyB5IGVsIHF1ZSBlc3R1ZGlhcmVtb3MgZW4gZXN0YSBtYXRlcmlhKSwgQVNTSVNUQU5ULCBDTFMgeSBJRDMvNC81LiBVbiDDoXJib2wgZGUgZGVjaXNpw7NuIHRhbWJpw6luIHNlIHB1ZWRlIGdlbmVyYXIgbWVkaWFudGUgbGEgY3JlYWNpw7NuIGRlIHJlZ2xhcyBkZSBhc29jaWFjacOzbiwgdWJpY2FuZG8gbGEgdmFyaWFibGUgb2JqZXRpdm8gYSBsYSBkZXJlY2hhLgoKQ2FkYSBtw6l0b2RvIGRlYmUgZGV0ZXJtaW5hciBjdcOhbCBlcyBsYSBtZWpvciBmb3JtYSBkZSBkaXZpZGlyIGxvcyBkYXRvcyBlbiBjYWRhIG5pdmVsLiBMb3MgbcOpdG9kb3MgY29tdW5lcyBwYXJhIGhhY2VybG8gaW5jbHV5ZW4gbGEgbWVkaWNpw7NuIGRlIGxhIGltcHVyZXphIGRlIEdpbmksIGxhIG9idGVuY2nDs24gZGUgaW5mb3JtYWNpw7NuIHkgbGEgcmVkdWNjacOzbiBkZSB2YXJpYWNpb25lcy4KCiMjIyBWZW50YWphcyB5IGRlc3ZlbnRhamFzCgpFbXBsZWFyIGxvcyDDoXJib2xlcyBkZSBkZWNpc2nDs24gZW4gZWwgYXByZW5kaXphamUgYXV0b23DoXRpY28gdGllbmUgbnVtZXJvc2FzICoqdmVudGFqYXMqKjoKCiogRWwgY29zdG8gZGVsIHVzbyBkZWwgw6FyYm9sIHBhcmEgcHJlZGVjaXIgbG9zIGRhdG9zIGRpc21pbnV5ZSBjb24gY2FkYSBwdW50byBkZSBkYXRvcyBhZGljaW9uYWwuCgoqIEZ1bmNpb25hIHBhcmEgbG9zIGRhdG9zIG51bcOpcmljb3MgbyBjYXRlZ8Ozcmljb3MuCgoqIFB1ZWRlIG1vZGVsYXIgcHJvYmxlbWFzIGNvbiBtw7psdGlwbGVzIHJlc3VsdGFkb3MuCgoqIFVzYSB1biBtb2RlbG8gZGUgY2FqYSBibGFuY2EgKGxvIHF1ZSBoYWNlIHF1ZSBsb3MgcmVzdWx0YWRvcyBzZWFuIGbDoWNpbGVzIGRlIGV4cGxpY2FyKS4gKkxvcyBhbGdvcml0bW9zIGNhamEgYmxhbmNhIHNvbiBhcXVlbGxvcyBxdWUgbm9ybWFsbWVudGUgdHJhYmFqYW4gc29icmUgZnVuY2lvbmVzIG1hdGVtw6F0aWNhcyBvIGRlIGzDs2dpY2EgcXVlIGVsIHByb2dyYW1hZG9yIGNvbm9jZSBtdXkgYmllbiB5IHF1ZSB2YSBtb2RpZmljYW5kbyBwYXJhIG1lam9yYXIgZWwgcmVuZGltaWVudG8gZGVsIGFsZ29yaXRtby4gKgoKKiBMYSBmaWFiaWxpZGFkIGRlIHVuIMOhcmJvbCBzZSBwdWVkZSBjdWFudGlmaWNhciB5IHBvbmVyIGEgcHJ1ZWJhLgoKKiBUaWVuZGUgYSBzZXIgcHJlY2lzbyBpbmRlcGVuZGllbnRlbWVudGUgZGUgc2kgdmlvbGEgbGFzIHN1cG9zaWNpb25lcyBkZSBsb3MgZGF0b3MgZGUgb3JpZ2VuLgoKClBlcm8gdGFtYmnDqW4gdGllbmVuIGFsZ3VuYXMgKipkZXN2ZW50YWphcyoqOgoKKiBDdWFuZG8gc2UgcHJlc2VudGFuIGRhdG9zIGNhdGVnw7NyaWNvcyBjb24gbcO6bHRpcGxlcyBuaXZlbGVzLCBsYSBpbmZvcm1hY2nDs24gb2J0ZW5pZGEgc2UgaW5jbGluYSBhIGZhdm9yIGRlIGxvcyBhdHJpYnV0b3MgY29uIG1heW9yw61hIGRlIG5pdmVsZXMuCgoqIExvcyBjw6FsY3Vsb3MgcHVlZGVuIHZvbHZlcnNlIGNvbXBsZWpvcyBhbCBsaWRpYXIgY29uIGxhIGZhbHRhIGRlIGNlcnRlemFzIHkgbnVtZXJvc29zIHJlc3VsdGFkb3MgcmVsYWNpb25hZG9zLgoKKiBMYXMgY29uanVuY2lvbmVzIGVudHJlIG5vZG9zIHNlIGxpbWl0YW4gYSBBTkQsIG1pZW50cmFzIHF1ZSBsb3MgZ3LDoWZpY29zIGRlIGRlY2lzacOzbiBhZG1pdGVuIG7Ds2R1bG9zIHJlbGFjaW9uYWRvcyBtZWRpYW50ZSBPUi4KCiMjIFBhcmEgdGVuZXIgZW4gY3VlbnRhIHNvYnJlIMOhcmJvbGVzCgoqIFNvbiB1biB0aXBvIGRlIGFsZ29yaXRtb3MgZGUgYXByZW5kaXphamUgc3VwZXJ2aXNhZG8gKGVzIGRlY2lyLCBleGlzdGUgdW5hIHZhcmlhYmxlIG9iamV0aXZvIHByZWRlZmluaWRhKS4KCiogUHJpbmNpcGFsbWVudGUgdXNhZG9zIGVuIHByb2JsZW1hcyBkZSBjbGFzaWZpY2FjacOzbi4KCiogTGFzIHZhcmlhYmxlcyBkZSBlbnRyYWRhIHkgc2FsaWRhIHB1ZWRlbiBzZXIgY2F0ZWfDs3JpY2FzIG8gY29udGludWFzLgoKKiBEaXZpZGUgZWwgZXNwYWNpbyBkZSBwcmVkaWN0b3JlcyAodmFyaWFibGVzIGluZGVwZW5kaWVudGVzKSBlbiByZWdpb25lcyBkaXN0aW50YXMgeSBubyBzb2JyZXB1ZXN0YXMuIFBvciBlamVtcGxvOgoKPGNlbnRlcj4KIVtdKC4vaW1hZ2VzL0VqZUFyYm9sLnBuZykKPC9jZW50ZXI+CgoqIFNlIGRpdmlkZSBsYSBwb2JsYWNpw7NuIG8gbXVlc3RyYSBlbiBjb25qdW50b3MgaG9tb2fDqW5lb3MgYmFzYWRvcyBlbiBsYSB2YXJpYWJsZSBkZSBlbnRyYWRhIG3DoXMgc2lnbmlmaWNhdGl2YS4KCiogTGEgY29uc3RydWNjacOzbiBkZWwgw6FyYm9sIHNpZ3VlIHVuIGVuZm9xdWUgZGUgZGl2aXNpw7NuIGJpbmFyaWEgcmVjdXJzaXZhICh0b3AtZG93biBncmVkZHkgYXBwcm9hY2gpLiBHcmVlZHkgLT4gYW5hbGl6YSBsYSBtZWpvciB2YXJpYWJsZSBwYXJhIHJhbWlmaWNhY2nDs24gc8OzbG8gZW4gZWwgcHJvY2VzbyBkZSBkaXZpc2nDs24gYWN0dWFsLgoKPGNlbnRlcj4KIVtdKC4vaW1hZ2VzL0NvbnN0QXJib2wucG5nKQo8L2NlbnRlcj4KCiMjIyBFamVtcGxvIAoKVGVuZW1vcyB1biBjb25qdW50byBkZSBkYXRvcyBjb3JyZXNwb25kaWVudGUgYSAzMCBlc3R1ZGlhbnRlcyB5IDMgdmFyaWFibGVzOiAKCipHw6luZXJvIChob21icmUvbXVqZXIpLCAKCipDbGFzZSAoSVgvWCkgeSAKCipBbHR1cmEgKDUgYSA2IHBpZXMpLiAKClNhYmVtb3MgcXVlIDE1IGVzdHVkaWFudGVzIGp1ZWdhbiBjcmlja2V0IGVuIHN1IHRpZW1wbyBsaWJyZS4gUXVlcmVtb3MgY3JlYXIgdW4gbW9kZWxvIHBhcmEgcHJlZGVjaXIgcXVpZW4ganVnYXLDoSBjcmlja2V0LiAKU2VncmVnYXIgZXN0dWRpYW50ZXMgYmFzYWRvcyBlbiB0b2RvcyBsb3MgdmFsb3JlcyBkZSBsYXMgMyB2YXJpYWJsZXMgZSBpZGVudGlmaWNhciBhcXVlbGxhIHZhcmlhYmxlIHF1ZSBjcmVhIGxvcyBjb25qdW50b3MgbcOhcyBob21vZ8OpbmVvcyBkZSBlc3R1ZGlhbnRlcyB5IHF1ZSBhIHN1IHZleiBzb24gaGV0ZXJvZ8OpbmVvcyBlbnRyZSBlbGxvcy4KCjxjZW50ZXI+CiFbXSguL2ltYWdlcy9FamVtcGxvQS5wbmcpCjwvY2VudGVyPgoKKirCv1F1w6kgdmFyaWFibGUgZXMgbGEgbcOhcyBzaWduaWZpY2F0aXZhIHBhcmEgbGEgbWVqb3IgZGl2aXNpw7NuIGRlIGxhIHBvYmxhY2nDs24/KioKCiMjIFRlcm1pbm9sb2fDrWEgYSBsYSBob3JhIGRlIG1vZGVsYXIKCipOb2RvIHJhw616OiBwb2JsYWNpw7NuIGNvbXBsZXRhIG8gbXVlc3RyYQoKKiBSYW1pZmljYWNpw7NuCgoqIE5vZG8gZGUgZGVjaXNpw7NuCgoqIE5vZG8gdGVybWluYWwgeSBob2phCgoqUG9kYQoKKlJhbWEvc3ViLcOhcmJvbAoKKk5vZG9zIHBhZHJlIGUgaGlqbwoKPGNlbnRlcj4KIVtdKC4vaW1hZ2VzL3Rlcm1pbm9sb2dpYS5wbmcpCjwvY2VudGVyPgoKCgojIMOBcmJvbGVzIGRlIHJlZ3Jlc2nDs24gdmVyc3VzIMOhcmJvbGVzIGRlIGNsYXNpZmljYWNpw7NuCgpFbCBtb2RlbG8gZGUgY29uanVudG8gZGUgw6FyYm9sZXMgY29uc3RhIGRlIHVuIGNvbmp1bnRvIGRlICrDoXJib2xlcyBkZSBjbGFzaWZpY2FjacOzbiB5IHJlZ3Jlc2nDs24gKENBUlQpKiwgZWwgY3VhbCBmdWUgZGVzYXJyb2xsYWRvIHBvciAqQnJlaW1hbiBldCBhbCogZW4gMTk4NC4gICAKCkFob3JhIGJpZW4sICrCv2N1w6FsIGVzIGxhIGRpZmVyZW5jaWEgZW50cmUgKsOhcmJvbGVzIGRlIGNsYXNpZmljYWNpw7NuIHkgcmVncmVzacOzbj8qCgoKfCBSZWdyZXNpw7NuICAgICAgICAgICAgIHwgQ2xhc2lmaWNhY2nDs24gICAgfCAKfC0tLS0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLXwKfCBWYXJpYWJsZSBhIHByZWRlY2lyIGVzIGNvbnRpbnVhICAgfCBWYXJpYWJsZSBhIHByZWRlY2lyIGVzIGNhdGVnw7NyaWNhICAgIHwKfCBWYWxvcmVzIGRlIGxvcyBub2RvcyB0ZXJtaW5hbGVzIHNlIHJlZHVjZW4gYSBsYSBtZWRpZGEgZGUgbGFzIG9ic2VydmFjaW9uZXMgZW4gZXNhIHJlZ2nDs24gICAgICAgIHwgRWwgdmFsb3IgZW4gZWwgbm9kbyB0ZXJtaW5hbCBzZSByZWR1Y2UgYSBsYSBtb2RhIGRlIGxhcyBvYnNlcnZhY2lvbmVzIGRlbCBjb25qdW50byBkZSBlbnRyZW5hbWllbnRvIHF1ZSBoYW4gKmxsZWdhZG8gbyBjYcOtZG8qIGVuIGxhIHJlZ2nDs24uICAgICAgIHwKCkVuIGxvcyDDoXJib2xlcyBkZSBkZWNpc2nDs24gY29tZW56YW1vcyBwb3IgdW5hIHByZWd1bnRhLiBBcXXDrSBoYXkgdW4gZWplbXBsbyBzaW1wbGUgZGUgdW4gQ0FSVCBxdWUgY2xhc2lmaWNhIHNpIGEgYWxndWllbiBsZSBndXN0YXLDoSB1biBoaXBvdMOpdGljbyBqdWVnbyBkZSBjb21wdXRhZG9yYSBYLCBkw7NuZGUgbGEgcHJlZ3VudGEgZXMgwr9MZSBndXN0YW4gbG9zIGp1ZWdvcyBkZSBjb21wdXRhZG9yYSBYPwoKPGNlbnRlcj4KIVtdKC4vaW1hZ2VzL0NBUlQxLnBuZykKPC9jZW50ZXI+CgpDbGFzaWZpY2Ftb3MgYSBsb3MgaW50ZWdyYW50ZXMgZGUgbnVlc3RybyBjb25qdW50byBkZSBkYXRvcyBlbiBkaWZlcmVudGVzIHJhbWFzIHNlZ8O6biBsYSBlZGFkIHkgc2UgbGEgYXNpZ25hIHVuYSBwdW50dWFjacOzbiBjb3JyZXNwb25kaWVudGUgZW4gZWwgdsOpcnRpY2UuIAoKVW4gKkNBUlQqIGVzIHVuIHBvY28gZGlmZXJlbnRlIGRlIGxvcyDDoXJib2xlcyBkZSBkZWNpc2nDs24sIGVuIGxvcyBxdWUgbGEgaG9qYSBzb2xvIGNvbnRpZW5lIHZhbG9yZXMgZGUgZGVjaXNpw7NuLiBFbiBDQVJULCBzZSBhc29jaWEgdW5hIHB1bnR1YWNpw7NuIHJlYWwgYSBjYWRhIHVuYSBkZSBsYXMgaG9qYXMsIGxvIHF1ZSBub3MgZGEgaW50ZXJwcmV0YWNpb25lcyBtw6FzIHJpY2FzIHF1ZSB2YW4gbcOhcyBhbGzDoSBkZSBsYSBjbGFzaWZpY2FjacOzbi4gRXN0byB0YW1iacOpbiBwZXJtaXRlIHVuIGVuZm9xdWUgdW5pZmljYWRvIHkgYmFzYWRvIGVuIHByaW5jaXBpb3MgcGFyYSBsYSBvcHRpbWl6YWNpw7NuLgoKUG9yIGxvIGdlbmVyYWwsIHVuIHNvbG8gw6FyYm9sIG5vIGVzIGxvIHN1ZmljaWVudGVtZW50ZSBmdWVydGUgcGFyYSB1c2Fyc2UgZW4gbGEgcHLDoWN0aWNhLiBMbyBxdWUgc2UgdXRpbGl6YSByZWFsbWVudGUgZXMgZWwgbW9kZWxvIGRlIGNvbmp1bnRvLCBxdWUgc3VtYSBsYSBwcmVkaWNjacOzbiBkZSB2YXJpb3Mgw6FyYm9sZXMganVudG9zLgoKQSBjb250aW51YWNpw7NuLHNlIG11ZXN0cmEgdW4gZWplbXBsbyBkZSB1biBjb25qdW50byBkZSBkb3Mgw6FyYm9sZXMuIExhcyBwdW50dWFjaW9uZXMgZGUgcHJlZGljY2nDs24gZGUgY2FkYSDDoXJib2wgaW5kaXZpZHVhbCBzZSBzdW1hbiBwYXJhIG9idGVuZXIgbGEgcHVudHVhY2nDs24gZmluYWwuIFNpIG1pcmFzIGVsIGVqZW1wbG8sIHVuIGRhdG8gaW1wb3J0YW50ZSBlcyBxdWUgbG9zIGRvcyDDoXJib2xlcyBpbnRlbnRhbiBjb21wbGVtZW50YXJzZS4KPGNlbnRlcj4KIVtdKC4vaW1hZ2VzL0NBUlQyLnBuZykKPC9jZW50ZXI+CgogTWF0ZW3DoXRpY2FtZW50ZSwgcG9kZW1vcyBlc2NyaWJpciBudWVzdHJvIG1vZGVsbyBlbiBsYSBmb3JtYQokJApcaGF0e3l9PSBcc3VtX3trPTF9XksgZl9rKHhfaSksIFxzcGFjZSBmX2sgXGluIFxkaWdhbW1hCiQkCmRvbmRlOgoKKiAkeF9pJCBlcyBlbCBpbmRpdmlkdW8gJGkkLAoKKiAkSyQgZXMgZWwgbsO6bWVybyBkZSDDoXJib2xlcywKCiogJGYkIGVzIHVuYSBmdW5jacOzbiBkZWwgZXNwYWNpbyBmdW5jaW9uYWwgJFxkaWdhbW1hJCwgeSAKCiogJFxkaWdhbW1hJCBlcyBlbCBjb25qdW50byBkZSB0b2RvcyBsb3MgQ0FSVCBwb3NpYmxlcy4gCgpTZSBidXNjYSBvcHRpbWl6YXIgdW5hIGZ1bmNpw7NuIG9iamV0aXZvIGRhZGEgcG9yOgoKJCQKb2JqKFx0aGV0YSkgPSAgXHN1bV97aT0xfV5uIGwoeV9pLFxoYXQgeV9pKStcc3VtX3trPTF9XksgXHZhck9tZWdhIChmX2spCiQkCgpkb25kZSBsYSBwcmltZXJhIHBhcnRlIHJlcHJlc2VudGEgbGEgcMOpcmRpZGEgZGVsIGVudHJlbmFtaWVudG8geSBsYSBzZWd1bmRhIGxhIHJlZ3VsYXJpemFjacOzbi4KCiMjIEF1bWVudG8gZGUgw6FyYm9sZXMKCllhIHRlbmllbmRvIHJlcHJlc2VudGFkbyBlbCBtb2RlbG8sIHBhc2Ftb3MgYWwgZW50cmVuYW1pZW50bzogKsK/Q8OzbW8gZGViZSBhcHJlbmRlciBsb3Mgw6FyYm9sZXM/KiBMYSByZXNwdWVzdGEgZXMsIGNvbW8gdG9kb3MgbG9zIG1vZGVsb3MgZGUgYXByZW5kaXphamUgc3VwZXJ2aXNhZG86ICoqKsKhZGVmaW5hIHVuYSBmdW5jacOzbiBvYmpldGl2byB5IG9wdGltw61jZWxhISoqKgoKU2VhIGxhIHNpZ3VpZW50ZSBmdW5jacOzbiBvYmpldGl2byAocmVjdWVyZGUgcXVlIHNpZW1wcmUgZGViZSBjb250ZW5lciBsYSBww6lyZGlkYSBkZSBlbnRyZW5hbWllbnRvIHkgbGEgcmVndWxhcml6YWNpw7NuKToKCiQkCm9iaiA9ICBcc3VtX3tpPTF9Xm4gbCh5X2ksXGhhdCB5X2leeyh0KX0pK1xzdW1fe2k9MX1edCBcdmFyT21lZ2EgKGZfaSkKJCQKCiMjIyBFbnRyZW5hbWllbnRvIGFkaXRpdm8KCkxhIHByaW1lcmEgcHJlZ3VudGEgcXVlIHF1ZXJlbW9zIGhhY2Vybm9zOiDCv2N1w6FsZXMgc29uIGxvcyAqKnBhcsOhbWV0cm9zKiogZGUgbG9zIMOhcmJvbGVzPyBQdWVkZSBlbmNvbnRyYXIgcXVlIGxvIHF1ZSBuZWNlc2l0YW1vcyBxdWUgYXByZW5kYSBzb24gZXNhcyBmdW5jaW9uZXMgJGZfaSQsIGNhZGEgdW5vIGNvbiBsYSBlc3RydWN0dXJhIGRlbCDDoXJib2wgeSBwdW50dWFjaW9uZXMgZW4gbGFzIGhvamFzLiBBcHJlbmRlciBsYSBlc3RydWN0dXJhIGRlbCDDoXJib2wgZXMgbXVjaG8gbcOhcyBkaWbDrWNpbCBxdWUgZWwgcHJvYmxlbWEgZGUgb3B0aW1pemFjacOzbiB0cmFkaWNpb25hbCBlbiBlbCBxdWUgc2ltcGxlbWVudGUgcHVlZGUgdG9tYXIgZWwgZ3JhZGllbnRlLiAqRXMgZGlmw61jaWwgcXVlIHNlIGFwcmVuZGEgdG9kb3MgbG9zIMOhcmJvbGVzIGFsIG1pc21vIHRpZW1wbyouIAoKUG9yIGVzbywgc2UgdXNhIHVuYSAqZXN0cmF0ZWdpYSBhZGl0aXZhKjogb3JnYW5pemFuZG8gbG8gcXVlIGhhIGFwcmVuZGlkbyB5IGFncmVnYSB1biDDoXJib2wgbnVldm8gYSBsYSB2ZXouIFNlIHZhIGVzY3JpYmllbmRvIGVsIHZhbG9yIGRlIHByZWRpY2Npw7NuIGVuIGVsIHBhc28gJHQkIGNvbW8gJFxoYXQgeV9pXnsodCl9JCAuIEVudG9uY2VzIHNlIHB1ZWRlIG9idGVuZXI6CgoKCiQkClxiZWdpbnthcnJheX17bH0KXGhhdCB5X2leeygwKX09MCBcXApcaGF0IHlfaV57KDEpfT1mXzEoeF9pKT1caGF0IHlfaV57MH0rZl8xKHhfaSkgXFwKXGhhdCB5X2leeygyKX09Zl8xKHhfaSkrZl8yKHhfaSk9XGhhdCB5X2leezF9K2YyaSh4X2kpClxlbmR7YXJyYXl9CiQkCgpFbnRvbmNlcyBhaG9yYSBub3MgZmFsdGEgwr9xdcOpIMOhcmJvbCBxdWVyZW1vcyBlbiBjYWRhIHBhc28/IGxvIG5hdHVyYWwgZXMgc3VtYXIgZWwgcXVlIG9wdGltaWNlIGxhIGZ1bmNpw7NuIG9iamV0aXZvCgokJApcYmVnaW57YWxpZ259Cm9ial57KHQpfSAmID0gIFxzdW1fe2k9MX1ebiBsKHlfaSxcaGF0IHlfaV57KHQpfSkrXHN1bV97aT0xfV50IFx2YXJPbWVnYSAoZl9pKSBcXAogICAgICAgICAgJiA9ICBcc3VtX3tpPTF9Xm4gbCh5X2ksXGhhdCB5X2leeyh0LTEpfStmX3QoeF9pKSkrIFx2YXJPbWVnYSAoZl90KSArIFx0ZXh0e2NvbnN0YW50fQpcZW5ke2FsaWdufQokJApTaSBjb25zaWRlcmFtb3MgZWwgdXNvIGRlbCBlcnJvciBjdWFkcsOhdGljbyBtZWRpbyAoTVNFKSBjb21vIGxhIGZ1bmNpw7NuIGRlIHDDqXJkaWRhLCBlbCBvYmpldGl2byBzZSBjb252aWVydGUgZW4KCiQkClxiZWdpbnthbGlnbn0Kb2JqXnsodCl9ICYgPSAgXHN1bV97aT0xfV5uICh5X2ktKFxoYXQgeV9pXnsodC0xKX0rZl90KHhfaSkpKV4yK1xzdW1fe2k9MX1edCBcdmFyT21lZ2EgKGZfaSkgXFwKICAgICAgICAgICYgPSAgXHN1bV97aT0xfV5uIFsyKFxoYXQgeV9pXnsodC0xKX0gLSB5X2kpZl90KHhfaSkrZl90KHhfaSleMl0rIFx2YXJPbWVnYSAoZl90KSArIFx0ZXh0e2NvbnN0YW50fQpcZW5ke2FsaWdufQokJApMYSBmb3JtYSBkZSBNU0UgZXMgYW1pZ2FibGUsIGNvbiB1biB0w6lybWlubyBkZSBwcmltZXIgb3JkZW4gKGdlbmVyYWxtZW50ZSBsbGFtYWRvIHJlc2lkdWFsKSB5IHVuIHTDqXJtaW5vIGN1YWRyw6F0aWNvLiBQYXJhIG90cmFzIHDDqXJkaWRhcyBkZSBpbnRlcsOpcyAocG9yIGVqZW1wbG8sIHDDqXJkaWRhIGxvZ8Otc3RpY2EpLCBubyBlcyB0YW4gZsOhY2lsIGNvbnNlZ3VpciB1bmEgZm9ybWEgdGFuIGJvbml0YS4gRW50b25jZXMsIGVuIGVsIGNhc28gZ2VuZXJhbCwgdG9tYW1vcyBsYSAqZXhwYW5zacOzbiBkZSBUYXlsb3IgZGUgbGEgZnVuY2nDs24gZGUgcMOpcmRpZGEgaGFzdGEgZWwgc2VndW5kbyBvcmRlbio6CgokJApvYmpeeyh0KX0gPSAgXHN1bV97aT0xfV5uIFtsKHlfaSxcaGF0IHlfaV57KHQtMSl9KStnX2lmX3QoeF9pKStcZnJhY3sxfXsyfWhfaWZfdF4yKHhfaSldICsgXHZhck9tZWdhIChmX3QpICsgXHRleHR7Y29uc3RhbnR9CiQkCgpkb25kZSwKJCQKXGJlZ2lue2FsaWdufQpnX2kgPSBccGFydGlhbF97XGhhdHt5fV9pXnsodC0xKX19bCh5X2ksXGhhdHt5fV9pXnt0LTF9KVxcCmhfaSA9IFxwYXJ0aWFsXjJfe1xoYXR7eX1faV57KHQtMSl9fWwoeV9pLFxoYXR7eX1faV57dC0xfSkKXGVuZHthbGlnbn0KJCQKRGVzcHXDqXMgZGUgZWxpbWluYXIgdG9kYXMgbGFzIGNvbnN0YW50ZXMsIGVsIG9iamV0aXZvIGVzcGVjw61maWNvIGVuIGVsIHBhc28gIHNlIGNvbnZpZXJ0ZSBlbgoKJCQKXHN1bV97aT0xfV5uW2dfaWZfdCh4X2kpK1xmcmFjezF9ezJ9aF9pZl90XjIoeF9pKV0rXHZhck9tZWdhIChmX3QpIAokJAoKRXN0ZSBzZSBjb252aWVydGUgZW4gbGEgZnVuY2nDs24gb2JqZXRpdm8gZGUgb3B0aW1pemFjacOzbiBwYXJhIGVsIG51ZXZvIMOhcmJvbC4gVW5hIHZlbnRhamEgaW1wb3J0YW50ZSBkZSBlc3RhIGRlZmluaWNpw7NuIGVzIHF1ZSBlbCB2YWxvciBkZSBsYSBmdW5jacOzbiBvYmpldGl2byBzb2xvIGRlcGVuZGUgZGUKIHkgJGdfaSQgeSAkaF9pJC4gQXPDrSBlcyBjb21vIGFsZ29yaXRtbyBjb21vICBgWEdCb29zdGAgYWRtaXRlIGZ1bmNpb25lcyBkZSBww6lyZGlkYSBwZXJzb25hbGl6YWRhcy4gU2UgcHVlZGUgb3B0aW1pemFyIGNhZGEgZnVuY2nDs24gZGUgcMOpcmRpZGEsIGluY2x1aWRhIGxhIHJlZ3Jlc2nDs24gbG9nw61zdGljYSB5IGxhIGNsYXNpZmljYWNpw7NuIHBvciBwYXJlcywgdXRpbGl6YW5kbyBleGFjdGFtZW50ZSBlbCBtaXNtbyBzb2x1Y2lvbmFkb3IgcXVlIHRvbWEgJGdfaSQgeSAkaF9pJCBjb21vIGVudHJhZGEhCgojIyMgTGEgcHVudHVhY2nDs24gZGUgZXN0cnVjdHVyYQoKQXF1w60gZXN0w6EgbGEgcGFydGUgbcOhZ2ljYSBkZSBsYSBkZXJpdmFjacOzbi4gRGVzcHXDqXMgZGUgcmVmb3JtdWxhciBlbCBtb2RlbG8gZGUgw6FyYm9sLCBwb2RlbW9zIGVzY3JpYmlyIGVsIHZhbG9yIG9iamV0aXZvIGNvbiBlbCAkdCQtdGggw6FyYm9sIGNvbW86CgokJApcYmVnaW57YWxpZ259Cm9ial57KHQpfSAmIFxhcHByb3ggXHN1bV97aT0xfXtufVtnX2l3X3txKHhfaSl9K1xmcmFjezF9ezJ9aF9pd14yX3txKHhfaSl9XStcZ2FtbWEgVCtcZnJhY3sxfXsyfVxsYW1iZGEgXHN1bV97aj0xfV5Ud14yX2ogXFwKICYgPSBcc3VtX3tqPTF9XlQgWyhcc3VtX3tpXGluIElfan1nX2kpd19qK1xmcmFjezF9ezJ9KFxzdW1fe2lcaW4gSV9qfWhfaStcbGFtYmRhKXdfal4yXStcZ2FtbWEgVApcZW5ke2FsaWdufQokJAoKZG9uZGUsICRJX2o9IFx7IGkgfHEoeF9pKT1qXH0kIGVzIGVsIGNvbmp1bnRvIGRlIMOtbmRpY2VzIGRlIHB1bnRvcyBkZSBkYXRvcyBhc2lnbmFkb3MgYSBsYSAkaiQtdGggaG9qYS4gIE9ic2VydmUgcXVlIGVuIGxhIHNlZ3VuZGEgbMOtbmVhIGhlbW9zIHNlIGNhbWJpYSBlbCDDrW5kaWNlIGRlIGxhIHN1bWEgcG9ycXVlIHRvZG9zIGxvcyBwdW50b3MgZGUgZGF0b3MgZW4gbGEgbWlzbWEgaG9qYSBvYnRpZW5lbiBsYSBtaXNtYSBwdW50dWFjacOzbi4gUG9kcsOtYW1vcyBjb21wcmltaXIgYcO6biBtw6FzIGxhIGV4cHJlc2nDs24gZGVmaW5pZW5kbyAkR19qID0gXHN1bV97aVxpbiBJX2p9Z19pJCB5ICRIX2ogPSBcc3VtX3tpXGluIElfan1oX2kkCgokJApvYmpeeyh0KX0gPSBcc3VtX3tqPTF9XlQgW0dfandfaitcZnJhY3sxfXsyfShIX2orXGxhbWJkYSl3X2peMl0rXGdhbW1hIFQKJCQKCkVuIGVzdGEgZWN1YWNpw7NuLCAkd19qJCBzb24gaW5kZXBlbmRpZW50ZXMgZW50cmUgc8OtLCBsYSBmb3JtYSAkR19qd19qKyBcZnJhY3sxfXsyfShIX2orXGxhbWJkYSl3X2peMiQgZXMgY3VhZHLDoXRpY2EsIHkgcG9yIHRhbnRvIHBvZGVtb3MgZW5jb250cmFyIGVsIG1lam9yICR3X2okIHBhcmEgbGEgZXN0cnVjdHVyYSBkYWRhICRxKHgpJCB5IHBvZGVtb3MgcmVkdXIgbGEgZnVuY2nDs24gb2JqZXRpdm8gZGUgbGEgc2lndWllbnRlIGZvcm1hOgoKJCQKXGJlZ2lue2FsaWdufQp3X2peKiAmPSAtXGZyYWN7R19qfXtIX2orXGxhbWJkYX0gXFwKb2JqXiogJj0gLSBcZnJhY3sxfXsyfVxzdW1fe2o9MX1eVCBcZnJhY3tHX2peMn17SF9qK1xsYW1iZGF9K1xnYW1tYSBUClxlbmR7YWxpZ259CiQkCkxhIMO6bHRpbWEgZWN1YWNpw7NuIG1pZGUgKnF1w6kgdGFuIGJ1ZW5hIGVzdHJ1Y3R1cmEgZGUgw6FyYm9sKiBlcyAkcSh4KSQ6Cgo8Y2VudGVyPgohW10oLi9pbWFnZXMvQ0FSVDMucG5nKQo8L2NlbnRlcj4KClRvZG8gZXN0byBzdWVuYSB1biBwb2NvIGNvbXBsaWNhZG8sIHZlYW1vcyBjw7NtbyBzZSBwdWVkZW4gY2FsY3VsYXIgbGFzIHB1bnR1YWNpb25lcyBwb3IgbWVkaW8gZGUgbGEgaW1hZ2VuLiBCw6FzaWNhbWVudGUsIHBhcmEgdW5hIGVzdHJ1Y3R1cmEgZGUgw6FyYm9sIGRldGVybWluYWRhLCBlbXB1amFtb3MgbGFzIGVzdGFkw61zdGljYXMgJGdfaSQgeSAkaF9pJCBhIGxhcyBob2phcyBhIGxhcyBxdWUgcGVydGVuZWNlbiwgc3VtZSBsYXMgZXN0YWTDrXN0aWNhcyB5IHVzZSBsYSBmw7NybXVsYSBwYXJhIGNhbGN1bGFyIHF1w6kgdGFuIGJ1ZW5vIGVzIGVsIMOhcmJvbC4gRXN0YSBwdW50dWFjacOzbiBlcyBjb21vIGxhIG1lZGlkYSBkZSBpbXB1cmV6YXMgZW4gdW4gw6FyYm9sIGRlIGRlY2lzacOzbiwgZXhjZXB0byBxdWUgdGFtYmnDqW4gdG9tYSBlbiBjdWVudGEgbGEgY29tcGxlamlkYWQgZGVsIG1vZGVsby4KCgojIyMgRXN0cnVjdHVyYSBkZWwgw6FyYm9sCgpMdWVnbyBkZSBtZWRpciBxdcOpIHRhbiBidWVubyBlcyBlbCDDoXJib2wsIGxvIGlkZWFsIHNlcsOtYSBlbnVtZXJhciB0b2RvcyBsb3Mgw6FyYm9sZXMgcG9zaWJsZXMgeSBlbGVnaXIgZWwgbWVqb3IuICBFbiBsYSBwcsOhY3RpY2Egc2FiZW1vcyBxdWUgbm8gZGViZW1vcyBoYWNlcmxvIHBvciBlbCBjb3N0ZSBjb21wdXRhY2lvbmFsIHF1ZSBpbXBsaWNhLgoKRXNwZWPDrWZpY2FtZW50ZSwgdHJhdGVtb3MgZGUgZGl2aWRpciB1bmEgaG9qYSBlbiBkb3MgaG9qYXMsIHkgbGEgcHVudHVhY2nDs24gcXVlIHNlIG9idGllbmUgZXMgCgokJApHYWluID0gXGZyYWN7MX17Mn0gXGxlZnRbIFxmcmFje0deMl9MfXtIX0wrXGxhbWJkYX0rXGZyYWN7R14yX1J9e0hfUitcbGFtYmRhfS0gXGZyYWN7KEdfTCtHX1IpXjJ9e0hfTCtIX1IrXGxhbWJkYX0gXHJpZ2h0XS1cZ2FtbWEKJCQKCkVzdGEgZsOzcm11bGEgc2UgcHVlZGUgZGVzY29tcG9uZXIgY29tbzoKCjEuIGxhIHB1bnR1YWNpw7NuIGVuIGxhIG51ZXZhIGhvamEgaXpxdWllcmRhLCAKCjIuIGxhIHB1bnR1YWNpw7NuIGVuIGxhIG51ZXZhIGhvamEgZGVyZWNoYSwgCgozLiBMYSBwdW50dWFjacOzbiBlbiBsYSBob2phIG9yaWdpbmFsLCB5IAoKNC4gcmVndWxhcml6YWNpw7NuIGVuIGxhIGhvamEgYWRpY2lvbmFsLiAKClBvZGVtb3MgdmVyIHVuIGhlY2hvIGltcG9ydGFudGUgYXF1w606IHNpIGxhIGdhbmFuY2lhIGVzIG1lbm9yIHF1ZSAkXGdhbW1hJCwgc2Vyw61hIG1lam9yIG5vIGFncmVnYXIgZXNhIHJhbWEuIAoKwqFFc3RhcyBzb24gZXhhY3RhbWVudGUgbGFzIHTDqWNuaWNhcyBkZSAqKipwb2RhKioqIGVuIG1vZGVsb3MgYmFzYWRvcyBlbiDDoXJib2xlcyEgQWwgdXRpbGl6YXIgbG9zIHByaW5jaXBpb3MgZGVsIGFwcmVuZGl6YWplIHN1cGVydmlzYWRvLCBuYXR1cmFsbWVudGUgcG9kZW1vcyBlbmNvbnRyYXIgbGEgcmF6w7NuIHBvciBsYSBxdWUgZXN0YXMgdMOpY25pY2FzIGZ1bmNpb25hbi4KClBhcmEgZGF0b3MgZGUgdmFsb3IgcmVhbCwgZ2VuZXJhbG1lbnRlIHF1ZXJlbW9zIGJ1c2NhciB1bmEgZGl2aXNpw7NuIMOzcHRpbWEuIFBhcmEgaGFjZXJsbyBkZSBtYW5lcmEgZWZpY2llbnRlLCBjb2xvY2Ftb3MgdG9kYXMgbGFzIGluc3RhbmNpYXMgZGUgZm9ybWEgb3JkZW5hZGEsIGNvbW8gZW4gbGEgc2lndWllbnRlIGltYWdlbi4KCjxjZW50ZXI+CiFbXSguL2ltYWdlcy9DQVJUNC5wbmcpCjwvY2VudGVyPgoKVW4gZXNjYW5lbyBkZSBpenF1aWVyZGEgYSBkZXJlY2hhIGVzIHN1ZmljaWVudGUgcGFyYSBjYWxjdWxhciBsYSBwdW50dWFjacOzbiBkZSBlc3RydWN0dXJhIGRlIHRvZGFzIGxhcyBwb3NpYmxlcyBzb2x1Y2lvbmVzIGRlIGRpdmlzacOzbiwgeSBwb2RlbW9zIGVuY29udHJhciBsYSBtZWpvciBkaXZpc2nDs24gZGUgbWFuZXJhIGVmaWNpZW50ZS4KCgojIyBWZW50YWphcyB5IGRlc3ZlbnRhamFzIHJlc3BlY3RvIGEgb3Ryb3MgYWxnb3JpdG1vcyBvIG1vZGVsb3MKCiMjIyBWZW50YWphcyAKCiogRsOhY2lsIGRlIGVudGVuZGVyCgoqIMOadGlsIGVuIGV4cGxvcmFjacOzbiBkZSBkYXRvczogaWRlbnRpZmljYXIgaW1wb3J0YW5jaWEgZGUgdmFyaWFibGVzIGEgcGFydGlyIGRlIGNpZW50b3MgZGUgdmFyaWFibGVzLgoKKiBNZW5vcyBsaW1waWV6YSBkZSBkYXRvczogb3V0bGllcnMgeSB2YWxvcmVzIGZhbHRhbnRlcyBubyBpbmZsdWVuY2lhbiBlbCBtb2RlbG8gKEEgdW4gY2llcnRvIGdyYWRvKQoKKiBFbCB0aXBvIGRlIGRhdG9zIG5vIGVzIHVuYSByZXN0cmljY2nDs24KCiogRXMgdW4gbcOpdG9kbyBubyBwYXJhbcOpdHJpY28gKGkuZS4sIG5vIGhheSBzdXBvc2ljacOzbiBhY2VyY2EgZGVsIGVzcGFjaW8gZGUgZGlzdHJpYnVjacOzbiB5IGxhIGVzdHJ1Y3R1cmEgZGVsIGNsYXNpZmljYWRvcikKCgojIyMgRGVzdmVudGFqYXMKCiogU29icmVhanVzdGUKCiogUMOpcmRpZGEgZGUgaW5mb3JtYWNpw7NuIGFsIGNhdGVnb3JpemFyIHZhcmlhYmxlcyBjb250aW51YXMKCiogUHJlY2lzacOzbjogbcOpdG9kb3MgY29tbyBTVk0geSBjbGFzaWZpY2Fkb3JlcyB0aXBvIGVuc2FtYmxhZG9yIGEgbWVudWRvIHRpZW5lbiB0YXNhcyBkZSBlcnJvciAzMCUgbcOhcyBiYWphcyBxdWUgQ0FSVCAoQ2xhc3NpZmljYXRpb24gYW5kIFJlZ3Jlc3Npb24gVHJlZXMpCgoqIEluZXN0YWJpbGlkYWQ6IHVuIHBlcXVlw7FvIGNhbWJpbyBlbiBsb3MgZGF0b3MgcHVlZGUgbW9kaWZpY2FyIGFtcGxpYW1lbnRlIGxhIGVzdHJ1Y3R1cmEgZGVsIMOhcmJvbC4gUG9yIGxvIHRhbnRvIGxhIGludGVycHJldGFjacOzbiBubyBlcyB0YW4gZGlyZWN0YSBjb21vIHBhcmVjZS4KCiMjIMK/Q8OzbW8gZGVjaWRlIHVuIMOhcmJvbCBkw7NuZGUgcmFtaWZpY2Fyc2U/CgpMYSBkZWNpc2nDs24gZGUgaGFjZXIgZGl2aXNpb25lcyBlc3RyYXTDqWdpY2FzIGFmZWN0YSBhbHRhbWVudGUgbGEgcHJlY2lzacOzbiBkZWwgw6FyYm9sLgpMb3MgY3JpdGVyaW9zIGRlIGRlY2lzacOzbiBzb24gZGlmZXJlbnRlcyBwYXJhIMOhcmJvbGVzIGRlIGNsYXNpZmljYWNpw7NuIHkgcmVncmVzacOzbi4KRXhpc3RlbiB2YXJpb3MgYWxnb3JpdG1vcyBwYXJhIGRlY2lkaXIgbGEgcmFtaWZpY2FjacOzbi4KTGEgY3JlYWNpw7NuIGRlIHN1Ym5vZG9zIGluY3JlbWVudGEgbGEgaG9tb2dlbmVpZGFkIGRlIGxvcyBzdWJub2RvcyByZXN1bHRhbnRlcy4gRXMgZGVjaXIsIGxhIHB1cmV6YSBkZWwgbm9kbyBzZSBpbmNyZW1lbnRhIHJlc3BlY3RvIGEgbGEgdmFyaWFibGUgb2JqZXRpdm8uCkFsIGZpbmFsLCBzZSBwcnVlYmEgbGEgZGl2aXNpw7NuIGNvbiB0b2RhcyBsYXMgdmFyaWFibGVzIHkgc2UgZXNjb2dlIGxhIHF1ZSBwcm9kdWNlIHN1Ym5vZG9zIG3DoXMgaG9tb2fDqW5lb3MuCgpBbGd1bm9zIGFsZ29yaXRtb3MgbcOhcyBjb211bmVzIHBhcmEgbGEgc2VsZWNjacOzbjogCgoqIMONbmRpY2UgR2luaSwgCgoqIENoaSBDdWFkcmFkbywgCgoqIEdhbmFuY2lhIGRlIGxhIGluZm9ybWFjacOzbiwgeSAKCiogUmVkdWNjacOzbiBlbiBsYSB2YXJpYW56YQoKIyMjIMONbmRpY2UgR2luaQoKRXN0ZSDDrW5kaWNlIHNlIGJhc2EgZW4gbGEgZXhwcmVzacOzbjogKuKAnFNpIHNlbGVjY2lvbmFtb3MgYWxlYXRvcmlhbWVudGUgZG9zIMOtdGVtcyBkZSB1bmEgcG9ibGFjacOzbiwgZW50b25jZXMgZXN0b3MgZGViZW4gc2VyIGRlIGxhIG1pc21hIGNsYXNlIHkgbGEgcHJvYmFiaWxpZGFkIGRlIGVzdG8gZXMgMSBzaSBsYSBwb2JsYWNpw7NuIGVzIHB1cmHigJ0qLgoKQWxndW5hcyBjb25zaWRlcmFjaW9uZXM6CgoxLiBWYXJpYWJsZSBvYmpldGl2byBjYXRlZ8OzcmljYTog4oCcU3VjY2Vzc+KAnSBvIOKAnEZhaWx1cmXigJ0KCjIuIFNvbG8gZGl2aXNpb25lcyBiaW5hcmlhcwoKMy4gQSBtYXlvciB2YWxvciBkZSDDrW5kaWNlIEdpbmksIG1heW9yIGxhIGhvbW9nZW5laWRhZAoKNC4gQ0FSVCAoQ2xhc3NpZmljYXRpb24gYW5kIFJlZ3Jlc3Npb24gVHJlZSkgdXNhIGVsIG3DqXRvZG8gZGUgR2luaSBwYXJhIGxhIGRpdmlzacOzbiBiaW5hcmlhLgoKUGFyYSBzdSBjw6FsY3Vsbzo6CgoxLiBDYWxjdWxhciBHaW5pIHBhcmEgbG9zIHN1Ym5vZG9zIHVzYW5kbyBsYSBmw7NybXVsYSBkZSBsYSBzdW1hIGRlIGxvcyBjdWFkcmFkb3MgZGUgcHJvYmFiaWxpZGFkIHBhcmEgc3VjY2VzcyB5IGZhaWx1cmUgJChwXjIgKyBxXjIpJC4KCjIuIENhbGN1bGFyIEdpbmkgcGFyYSBsYSBkaXZpc2nDs24gdXNhbmRvIHNjb3JlIEdpbmkgcG9uZGVyYWRvIHBhcmEgY2FkYSBub2RvIGRlIGxhIGRpdmlzacOzbi4KClBhcmEgZW50ZW5kZXIgbWVqb3IgdG9kbyBlc3RvLCB2ZWFtb3MgdW4gZWplbXBsbzoKCjxjZW50ZXI+CiFbXSguL2ltYWdlcy9leGFtcGxlX3RyZWUucG5nKQo8L2NlbnRlcj4KCnwgR8OpbmVybyAgICAgICAgICAgICAgICAgICAgICAgfCBDbGFzZSAgICAgICAgICAgICAgICAgICAgICB8IAp8LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS18CnwgTXVqZXIgJDAuMl4yKzAuOF4yPTAuNjgkICAgICB8ICBJWCAgJDAuNDNeMiswLjU3XjI9MC41MSQgIHwKfCBIb21icmUgJDAuNjVeMiswLjM1XjI9MC41NSQgIHwgIFggICQwLjU2XjIrMC40NF4yPTAuNTEkICB8CnwgUG9uZC4gJCgxMC8zMCkwLjY4KygyMC8zMCkwLjU1ID0gMC41OSQgIHwgIFBvbmQuICQoMTQvMzApMC41MSArICgxNi8zMCkwLjUxID0gMC41MSQgIHwKCiogwr9DdcOhbCBlcyBlbCByZXN1bHRhZG8gcGFyYSBsYSB2YXJpYWJsZSDigJxBbHR1cmHigJ0/CgoqIMK/Q3XDoWwgZXMgZWwgdmFyaWFibGUgcXVlIHNlIGRlYmUgZXNjb2dlciBwYXJhIGxhIHByaW1lcmEgZGl2aXNpw7NuPwoKIyMjIENoaSBjdWFkcmFkbwoKVW4gYWxnb3JpdG1vIHBhcmEgZW5jb250cmFyIGxhIHNpZ25pZmljYW5jaWEgZXN0YWTDrXN0aWNhIGRlIGxhcyBkaWZlcmVuY2lhcyBlbnRyZSBzdWJub2RvcyB5IHVuIG5vZG8gcGFkcmUuIFNlIG1pZGUgYSBwYXJ0aXIgZGUgbGEgc3VtYSBkZSBsb3MgY3VhZHJhZG9zIGRlIGxhcyBkaWZlcmVuY2lhcyBlc3RhbmRhcml6YWRhcyBlbnRyZSBsYXMgZnJlY3VlbmNpYXMgb2JzZXJ2YWRhcyB5IGVzcGVyYWRhcyBkZSBsYSB2YXJpYWJsZSBvYmpldGl2by4KCkFsZ3VuYXMgY29uc2lkZXJhY2lvbmVzOiAKCjEuIFZhcmlhYmxlIG9iamV0aXZvIGNhdGVnw7NyaWNhIOKAnFN1Y2Nlc3PigJ0gbyDigJxGYWlsdXJl4oCdLgoKMi4gRG9zIG8gbcOhcyBkaXZpc2lvbmVzCgoyLiBBIG3DoXMgYWx0byB2YWxvciBkZSBDaGktQ3VhZHJhZG8sIG3DoXMgYWx0YSBsYSBzaWduaWZpY2FuY2lhIGVzdGFkw61zdGljYSBkZSBsYXMgZGlmZXJlbmNpYXMgZW50cmUgY2FkYSBub2RvIHkgZWwgbm9kbyBwYWRyZS4KCjMuIEbDs3JtdWxhOiAkXGxlZnRbXGZyYWN7KFJlYWwtRXNwZXJhZG8pXjJ9e0VzcGVyYWRvfSBccmlnaHRdXntcZnJhY3sxfXsyfX0kCgpQYXJhIHN1IGPDoWxjdWxvOgoKMS4gQ2FsY3VsYXIgQ2hpLUN1YWRyYWRvIHBhcmEgY2FkYSBub2RvIGluZGl2aWR1YWxtZW50ZSBhIHRyYXbDqXMgZGUgbGEgZGVzdmlhY2nDs24gcGFyYSBhbWJvczogU3VjY2VzcyB5IEZhaWx1cmUKCjIuIENhbGN1bGFyIENoaS1DdWFkcmFkbyBkZSBsYSBkaXZpc2nDs24gdXNhbmRvIGxhIHN1bWEgZGUgdG9kb3MgbG9zIENoaS1DdWFkcmFkbyBkZSBTdWNjZXNzIHkgRmFpbHVyZSBkZSBjYWRhIG5vZG8gZW4gbGEgZGl2aXNpw7NuLgoKQ29udGludWFuZG8gY29uIGVsIGVqZW1wbG8gYW50ZXJpb3IsIHBlcm8gdGVuaWVuZG8gbGFzIHNpZ3VpZW50ZXMgY29uc2lkZXJhY2lvbmVzOgoKMS4gUGFyYSBlbCBub2RvIOKAnE11amVy4oCdLiBMb3MgdmFsb3JlcyByZWFsZXMgcGFyYSDigJxQbGF5IENyaWNrZXTigJ0geSDigJxOb3QgUGxheSBDcmlja2V04oCdIHNvbiAyIHkgOCwgcmVzcGVjdGl2YW1lbnRlLgoKMi4gUGFyYSBjYWxjdWxhciBlbCB2YWxvciBlc3BlcmFkbywgYXNpZ25hcmVtb3MgbGEgbWlzbWEgcHJvYmFiaWxpZGFkIHF1ZSBzdSBub2RvIHBhZHJlICg1MCUpLiBQb3IgbG8gdGFudG8gcGFyYSBhbWJvcyBjYXNvcyBlbCB2YWxvciBzZXLDrWEgNSBjb25zaWRlcmFuZG8gZWwgdG90YWwgZGUgZWxlbWVudG9zIOKAnE11amVy4oCdICgxMCkuCgozLiBDYWxjdWxhciBsYXMgZGlmZXJlbmNpYXMgcGFyYSB1c2FyIGVuIGxhIGbDs3JtdWxhLCBSZWFsLUVzcGVyYWRvLiBQYXJhIOKAnFBsYXkgQ3JpY2tldOKAnSAoMi01PS0zKSB5IHBhcmEg4oCcTm8gUGxheSBDcmlja2V04oCdICg4LTU9MykKCjQuIENhbGN1bGFyIENoaS1DdWFkcmFkbyBkZWwgbm9kbyBwYXJhIOKAnFBsYXkgQ3JpY2tldOKAnSB5IOKAnE5vIFBsYXkgQ3JpY2tldOKAnSB1c2FuZG8gbGEgZsOzcm11bGEgY29tcGxldGEgJFxsZWZ0W1xmcmFjeyhSZWFsLUVzcGVyYWRvKV4yfXtFc3BlcmFkb30gXHJpZ2h0XV57XGZyYWN7MX17Mn19JC4KCjUuIFNlZ3VpciBsb3MgcGFzb3MgMS00IHBhcmEgZWwgY2FzbyBkZWwgbm9kbyDigJxIb21icmXigJ0uCgo2LiBmaW5hbG1lbnRlIHN1bWFyIHRvZG9zIGxvcyBDaGktQ3VhZHJhZG8gcGFyYSBjYWxjdWxhciBlbCBDaGktQ3VhZHJhZG8gcGFyYSBsYSBkaXZpc2nDs24gZGUgbGEgdmFyaWFibGUgR8OpbmVyby4KCnwgTm9kbyAgIHwgUGxheSBDcmlja2V0IHwgTm90IFBsYXkgfFRvdGFsIHwgRXhwZWN0ZWQgcGxheSB8IEV4cGVjdGVkIG5vdCBwbGF5IHwgRGV2aWF0aW9uIG5vdCBwbGF5IHwgQ2hpIFNxdWFyZSBwbGF5IHwgQ2hpIFNxdWFyZSBub3QgcGxheSB8CnwtLS0tLS0tLXwtLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tfC0tLS0tLXwtLS0tLS0tLS0tLS0tLS18LS0tLS0tfCAtLS0tLS18IC0tLS0tLXwgLS0tLS0tfCAKfCBGZW1hbGUgfCAgMiAgICAgICAgICAgfCA4ICAgICAgICB8IDEwICAgfCAgNSAgICB8IDUgICAgICAgIHwgLSAzICB8IDEuMzQgfCAxLjM0IHwKfCBNYWxlICAgfCAgMTMgICAgICAgICAgfCA3ICAgICAgICB8IDIwICAgfCAxMCAgICB8IDEwICAgICAgICB8ICAgMyAgfCAwLjk1IHwgMC45NSB8CgpQb3IgbG8gdGFudG8gZWwgdG90YWwgQ2hpIGN1YWRyYWRvIGVzIDQuNTguCgpQb2RlbW9zIGhhY2VyIGVsIG1pc21vIHByb2NlZGltaWVudG8gcGFyYSBsYSB2YXJpYWJsZSAiQ2xhc3MiOgoKfCBOb2RvICAgfCBQbGF5IENyaWNrZXQgfCBOb3QgUGxheSB8VG90YWwgfCBFeHBlY3RlZCBwbGF5IHwgRXhwZWN0ZWQgbm90IHBsYXkgfCBEZXZpYXRpb24gbm90IHBsYXkgfCBDaGkgU3F1YXJlIHBsYXkgfCBDaGkgU3F1YXJlIG5vdCBwbGF5IHwKfC0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS18LS0tLS0tfC0tLS0tLS0tLS0tLS0tLXwtLS0tLS18IC0tLS0tLXwgLS0tLS0tfCAtLS0tLS18CnwgSVggfCA2ICB8IDggfCAxNCB8IDcgfCAtMSB8ICAxIHwgMC4zOCB8IDAuMzggfCAKfCBYICB8IDkgIHwgNyB8IDE2IHwgOCB8ICAxIHwgLTEgfCAwLjM1IHwgMC4zNSB8CgpQb3IgbG8gdGFudG8gZWwgdG90YWwgQ2hpIGN1YWRyYWRvIGVzIDEuNDYuCgoqIMK/Q3XDoWwgZXMgZWwgcmVzdWx0YWRvIHBhcmEgbGEgdmFyaWFibGUg4oCcQWx0dXJh4oCdPwoKKiDCv0N1w6FsIGVzIGVsIHZhcmlhYmxlIHF1ZSBzZSBkZWJlIGVzY29nZXIgcGFyYSBsYSBwcmltZXJhIGRpdmlzacOzbj8KCiMjIyBHYW5hbmNpYSBkZSBpbmZvcm1hY2nDs24KClVuIG5vZG8gbWVub3MgaW1wdXJvIHJlcXVpZXJlIG1lbm9zIGluZm9ybWFjacOzbiBwYXJhIHNlciBkZXNjcml0byBtaWVudHJhcyB1biBub2RvIG3DoXMgaW1wdXJvIG5lY2VzaXRhIG3DoXMgaW5mb3JtYWNpw7NuLgpMYSB0ZW9yw61hIGRlIGxhIGluZm9ybWFjacOzbiBlcyB1bmEgbWVkaWRhIHBhcmEgZGVmaW5pciBlc3RlIGdyYWRvIGRlIGRlc29yZ2FuaXphY2nDs24gZW4gdW4gc2lzdGVtYSBkZW5vbWluYWRvIGNvbW8gRW50cm9ww61hLgpEZWNpbW9zIHF1ZSB1bmEgbXVlc3RyYSBjb21wbGV0YW1lbnRlIGhvbW9nw6luZWEgPSBlbnRyb3DDrWEgMCwgeSBkZWNpbW9zIHF1ZSBlcyBpZ3VhbG1lbnRlIGRpdmlkaWRhICg1MCUg4oCTIDUwJSkgPSBlbnRyb3DDrWEgMS4KPGNlbnRlcj4KIVtdKC4vaW1hZ2VzL2VudHJvcHkuanBlZykKPC9jZW50ZXI+CgpMYSBlbnRyb3DDrWEgbGEgcG9kZW1vcyBjYWxjdWxhciBkZSBsYSBzaWd1aWVudGUgZm9ybWE6CgokJApcdGV4dHtlbnRyb3BpYX0gPSAtcCBcbG9nXzIocCkgLSBxXGxvZ18yKHEpCiQkCgpkb25kZSAkcCQgZXMgbGEgcHJvYmFiaWxpZGFkIGRlICpzdWNjZXNzKiB5ICRxJCBsYSBwcm9iYWJpbGlkYWQgZGUgKmZhaWx1cmUqLiBMYSBlbnRyb3DDrWEgZXMgdGFtYmnDqW4gdXNhZGEgY29uIHZhcmlhYmxlIG9iamV0aXZvIGNhdGVnw7NyaWNhLiAgU2UgZXNjb2dlIGxhIGRpdmlzacOzbiBjb24gbGEgZW50cm9ww61hIG3DoXMgYmFqYSBjb21wYXJhZGEgY29uIGVsIG5vZG8gcGFkcmUgeSBvdHJhcyB2YXJpYWJsZXMgZGUgZGl2aXNpw7NuLiAgCgpQYXJhIGNhbGN1bGFyIGVudHJvcMOtYSBkZWwgbm9kbyBwYWRyZSwgY2FsY3VsYW1vcyBsYSBlbnRyb3DDrWEgZGUgY2FkYSB1bm8gZGUgbG9zIG5vZG9zIGRlIGZvcm1hIGluZGl2aWR1YWwgeSBjYWxjdWxhciBsYSBtZWRpYSBwb25kZXJhZGEgZGUgdG9kb3MgbG9zIG5vZG9zIGRpc3BvbmlibGVzIGVuIGxhIGRpdmlzacOzbi4KCkNvbnRpbnVhbmRvIGNvbiBlbCBlamVtcGxvLAoKfCBDcml0ZXJpbyAgfCBFbnRyb3DDrWEgfAp8LS0tLS0tLS0tLS18LS0tLS0tLS0tLXwKfE5vZG8gcGFkcmUgfCAtKDE1LzMwKSBsb2cyKDE1LzMwKS0oMTUvMzApIGxvZzIoMTUvMzApPSAxfAp8Tm9kbyBtdWplciB8LSgyLzEwKWxvZzIoMi8xMCktKDgvMTApbG9nMig4LzEwKT0wLjcyfAp8Tm9kbyBob21icmUgfCAtKDEzLzIwKSBsb2cyICgxMy8yMCkg4oCTICg3LzIwKSBsb2cyICg3LzIwKSA9IDAuOTN8CnxHw6luZXJvIHBvbmRlcmFkbyB8CSgxMC8zMCkwLjcyICsgKDIwLzMwKTAuOTMgPSAwLjg2IHwKfE5vZG8gQ2xhc2UgSVggfAktKDYvMTQpIGxvZzIgKDYvMTQpIOKAkyAoOC8xNCkgbG9nMiAoOC8xNCkgPSAwLjk5IHwKfCBOb2RvIENsYXNlIFgJfCAtKDkvMTYpIGxvZzIgKDkvMTYpIOKAkyAoNy8xNikgbG9nMiAoNy8xNikgPSAwLjk5IHwKfCBDbGFzZSBwb25kZXJhZG8JfCAoMTQvMzApMC45OSArICgxNi8zMCkwLjk5ID0gMC45OSB8CgpMYSBlbnRyb3DDrWEgcGFyYSBsYSBkaXZpc2nDs24gcG9yIGxhIHZhcmlhYmxlIOKAnEfDqW5lcm/igJ0gZXMgbGEgbcOhcyBiYWphLiBTZSBwdWVkZSBkZXJpdmFyIGxhIGdhbmFuY2lhIGRlIGluZm9ybWFjacOzbiBhIHBhcnRpciBkZSBsYSBlbnRyb3DDrWEgYXPDrTogMS1FbnRyb3DDrWEuCgojIyMgUmVkdWNjacOzbiBlbiBsYSB2YXJpYW56YSAocmVncmVzacOzbikKCkxvcyBhbGdvcml0bW9zIGFudGVyaW9yZXMgc2UgYXBsaWNhYmFuIHBhcmEgcHJvYmxlbWFzIGRlIGNsYXNpZmljYWNpw7NuIGNvbiB2YXJpYWJsZXMgb2JqZXRpdm8gY2F0ZWfDs3JpY2EuIFBvciBvdHJhIHBhcnRlLCBsYSByZWR1Y2Npw7NuIGVuIGxhIHZhcmlhbnphIGVzIHVuIGFsZ29yaXRtbyB1c2FkbyBwYXJhIHZhcmlhYmxlcyBvYmpldGl2byBjb250aW51YXMgKHByb2JsZW1hcyBkZSByZWdyZXNpw7NuKS4gRXN0ZSBhbGdvcml0bW8gdXNhIGxhIGbDs3JtdWxhIGVzdMOhbmRhciBkZSBsYSB2YXJpYW56YSBwYXJhIGVzY29nZXIgZWwgY3JpdGVyaW8gZGUgZGl2aXNpw7NuLiBMYSBkaXZpc2nDs24gY29uIGxhIHZhcmlhbnphIG3DoXMgYmFqYSBzZSBlc2NvZ2UgcGFyYSBkaXZpZGlyIGxhIHBvYmxhY2nDs246CgokJApcdGV4dHtWYXJpYW56YX09IFxmcmFje1xzdW0oWC1cYmFye1h9KV4yfXtufQokJAoKUGFyYSBzdSBjw6FsY3VsbyBwcmltZXJvIGNhbGN1bGFtb3MgbGEgdmFyaWFuemEgZW4gY2FkYSBub2RvLCBwYXJhIGx1ZWdvIGNhbGN1bGFyIGxhIHZhcmlhbnphIGRlIGNhZGEgZGl2aXNpw7NuIHBvciB1biBwcm9tZWRpbyBwb25kZXJhZG8gZGUgbGFzIHZhcmlhbnphcyBkZSBsb3Mgbm9kb3MuCgpDb250aW51YW5kbyBjb24gZWwgZWplbXBsbywgYXN1bWlyZW1vcyBxdWUgdmFtb3MgYSBjb252ZXJ0aXIgbG9zIHZhbG9yZXMgbnVtw6lyaWNvcyBkZSAxIHBhcmEgcGxheSBjcmlja2V0IHkgY2VybyBwYXJhIG5vIHBsYXkgY3JpY2tldC4KCgp8IENyaXRlcmlvfAlNZWFuCXxWYXJpYW56YXwKfC0tLS0tLS0tLXwtLS0tLS0tfC0tLS0tLS0tLXwKfE5vZG8gUGFkcmUJfCgxNXgxICsgMTV4MCkvMzAgPSAwLjV8CSgxNXgoMS0wLjUpXjIgKyAxNXgoMC0wLjUpXjIpIC8gMzAgPSAwLjI1fAp8Tm9kbyBNdWplcgl8KDJ4MSArIDh4MCkvMTA9MC4yfAkoMngoMS0wLjIpXjIgKyA4eCgwLTAuMileMikgLyAxMCA9IDAuMTZ8CnxOb2RvIEhvbWJyZXwJKDEzeDEgKyA3eDApLzIwPTAuNjV8CSgxM3goMS0wLjY1KV4yICsgNyooMC0wLjY1KV4yKSAvIDIwID0gMC4yM3wKfEfDqW5lcm8gcG9uZGVyYWRvCXx8CSgxMC8zMCl4MC4xNiArICgyMC8zMCkgKjAuMjMgPSAwLjIxfAp8Tm9kbyBDbGFzZSBJWHwJKDZ4MSArIDh4MCkvMTQ9MC40M3wJKDZ4KDEtMC40MyleMiArIDh4KDAtMC40MyleMikgLyAxND0gMC4yNHwKfE5vZG8gQ2xhc2UgWHwJKDl4MSArIDd4MCkvMTY9MC41Ngl8KDl4KDEtMC41NileMiArIDd4KDAtMC41NileMikgLyAxNiA9IDAuMjV8CnxDbGFzZSBwb25kZXJhZG8JfAl8KDE0LzMwKXgwLjI0ICsgKDE2LzMwKSB4MC4yNSA9IDAuMjV8CgojIyBQYXLDoW1ldHJvcyBkZWwgbW9kZWxvIHkgY29tbyBldml0YXIgc29icmVhanVzdGUgZW4gw6FyYm9sZXMgZGUgZGVjaXNpw7NuCgpFbCBzb2JyZWFqdXN0ZSBlcyB1bm8gZGUgbG9zIGRlc2Fmw61vcyBtw6FzIGltcG9ydGFudGVzIGVuIGVsIHByb2Nlc28gZGUgbW9kZWxhY2nDs24gZGUgw6FyYm9sZXMgZGUgZGVjaXNpw7NuLiBTaSBubyBzZSBkZWZpbmVuIGzDrW1pdGVzLCBlbCDDoXJib2wgdGVuZHLDoSB1biAxMDAlIGRlIHByZWNpc2nDs24gZW4gZWwgY29uanVudG8gZGUgZGF0b3MgZGUgZW50cmVuYW1pZW50by4gRW4gZWwgcGVvciBjYXNvIHRlbmRyw6EgdW5hIGhvamEgcG9yIGNhZGEgb2JzZXJ2YWNpw7NuLgoKRG9zIGZvcm1hcyBkZSBldml0YXIgZWwgc29icmVhanVzdGU6IChhKSBEZWZpbmlyIHJlc3RyaWNjaW9uZXMgc29icmUgZWwgdGFtYcOxbyBkZWwgw6FyYm9sIHkgKGIpIFBvZGFyIGVsIMOhcmJvbC4KCiMjIyBEZWZpbmlyIHJlc3RyaWNjaW9uZXMgc29icmUgZWwgdGFtYcOxbyBkZWwgw6FyYm9sIChwcmVwcnVuaW5nKQoKVXNvIGRlIHBhcsOhbWV0cm9zIHBhcmEgZGVmaW5pciB1biDDoXJib2wuIExvcyBwYXLDoW1ldHJvcyBzb24gaW5kZXBlbmRpZW50ZXMgZGUgbGEgaGVycmFtaWVudGEgZGUgcHJvZ3JhbWFjacOzbiAoUiAmIFB5dGhvbikKCjEuIE3DrW5pbW8gZGUgb2JzZXJ2YWNpb25lcyBwYXJhIGRpdmlkaXIgdW4gbm9kbwoKKiBNw61uaW1vIG7Dum1lcm8gZGUgbXVlc3RyYXMgdSBvYnNlcnZhY2lvbmVzIHF1ZSBzZSByZXF1aWVyZW4gZW4gdW4gbm9kbyBwYXJhIHNlciBjb25zaWRlcmFkbyBwYXJhIHJhbWlmaWNhY2nDs24uCgoqIFZhbG9yZXMgbcOhcyBhbHRvcyBwcmV2aWVuZW4gcXVlIGVsIG1vZGVsbyBhcHJlbmRhIHJlbGFjaW9uZXMgbXV5IGVzcGVjw61maWNhcy4KCiogVmFsb3JlcyBkZW1hc2lhZG8gYWx0b3MgcHVlZGVuIGNhdXNhciB1biBwb2JyZSBhanVzdGUgZGVsIG1vZGVsby4gRWwgcGFyw6FtZXRybyBkZWJlIGFqdXN0YXJzZSB1c2FuZG8gdmFsaWRhY2nDs24gY3J1emFkYS4KCjIuIE3DrW5pbW8gbsO6bWVybyBkZSBvYnNlcnZhY2lvbmVzIHBhcmEgdW4gbm9kbyB0ZXJtaW5hbAoKKiBWYWxvcmVzIG3DoXMgYmFqb3Mgc29uIG5lY2VzYXJpb3MgcGFyYSBwcm9ibGVtYXMgZGUgY2xhc2VzIG5vIGJhbGFuY2VhZGFzLgoKMy4gTcOheGltYSBwcm9mdW5kaWRhZCBkZWwgw6FyYm9sICh2ZXJ0aWNhbCkKCiogVW5hIG1heW9yIHByb2Z1bmRpZGFkIHBlcm1pdGUgYXByZW5kZXIgcmVsYWNpb25lcyBtw6FzIGVzcGVjw61maWNhcy4KCiogRGViZSBhanVzdGFyc2UgY29uIHZhbGlkYWNpw7NuIGNydXphZGEuCgo0LiBNw6F4aW1vIG7Dum1lcm8gZGUgbm9kb3MgaG9qYQoKKiBTZSBwdWVkZSBkZWZpbmlyIGVuIGx1Z2FyIGRlIG3DoXhpbWEgcHJvZnVuZGlkYWQuIFByb2Z1bmRpZGFkIG4gPSBtw6F4aW1vIDJebiBob2phcwoKNS4gTcOheGltbyBuw7ptZXJvIGRlIGF0cmlidXRvcyBhIGNvbnNpZGVyYXIgcGFyYSBsYSByYW1pZmljYWNpw7NuCgoqIFNlbGVjY2lvbmFkb3MgYWxlYXRvcmlhbWVudGUuCgoqIENvbW8gcmVnbGEgZ2VuZXJhbCwgbGEgcmHDrXogY3VhZHJhZGEgZGVsIG7Dum1lcm8gdG90YWwgZGUgYXRyaWJ1dG9zIGZ1bmNpb25hIGFwcm9waWFkYW1lbnRlLiBTaW4gZW1iYXJnbywgc2UgZGViZSBwcm9iYXIgaGFzdGEgdW4gMzAlLTQwJSBkZWwgbsO6bWVybyB0b3RhbCBkZSBhdHJpYnV0b3MuCgojIyBQb2RhIGRlbCDDoXJib2wgKHBvc3RwcnVuaW5nKQoKIFN1IGltcGxlbWVudGFjacOzbiBlcyBzZW5jaWxsYS4KCiogQ29uc3RydWlyIGVsIMOhcmJvbCBhIHVuIHByb2Z1bmRpZGFkIGV4dGVuc2EuCgoqIFJlbW92ZXIgbGFzIGhvamFzIHF1ZSBkZW4gdW4gdmFsb3IgbmVnYXRpdm8gY29tcGFyYWRvIGRlc2RlIGxhIHJhw616LiBFeGlzdGVuIHZhcmlvcyBjcml0ZXJpb3MgcXVlIHB1ZWRlbiBzZXIgdXRpbGl6YWRvcywgYWxndW5vcyBiYXNhZG9zIGVuIGhldXLDrXN0aWNhcyB5IG90cm9zIGVuIHBhcsOhbWV0cm9zIGRlIHJlZ3VsYXJpemFjacOzbiAocGVuYWxpemFjacOzbikuCgpFamVtcGxvOiBTdXBvbmdhbW9zIHF1ZSB1biBub2RvIGRlIGRlY2lzacOzbiBkYSB1bmEgZ2FuYW5jaWEgZGUgLTEwIChww6lyZGlkYSBkZSAxMCkgeSBsYSBzaWd1aWVudGUgcmFtaWZpY2FjacOzbiBkYSB1bmEgZ2FuYW5jaWEgZGUgMjAuIFVuIMOhcmJvbCBkZSBkZWNpc2nDs24gc2ltcGxlIHBhcmFyw61hIGVuIGVsIHBhc28gdW5vLCBzaW4gZW1iYXJnbywgZWwgcHJvY2VzbyBkZSBwb2RhIGNvbnNpZGVyYXLDoSBsYSBnYW5hbmNpYSBnZW5lcmFsIGRlICsxMCB5IG1hbnRlbmRyw6EgYW1iYXMgaG9qYXMuCgpMaWJyZXLDrWFzOiBFbCBjbGFzaWZpY2Fkb3IgZGUgw6FyYm9sIGRlIGRlY2lzacOzbiBlbiBsYSBsaWJyYXLDrWEgZGUgcHl0aG9uIFNjaWtpdCBhY3R1YWxtZW50ZSBubyBzb3BvcnRhIGVsIHByb2Nlc28gZGUgcG9kYS4gUGFxdWV0ZXMgYXZhbnphZG9zIGNvbW8gYHhnYm9vc3RgIGxvIGluY29wb3Jhbi4gUG9yIG90cmEgcGFydGUsIGVsIHBhcXVldGUgZGUgUiBgcnBhcnRgIHByb3ZlZSB1bmEgZnVuY2nDs24gZGUgcG9kYSBkaXJlY3RhbWVudGUuCgoKIyBSZWZlcmVuY2lhcwoKKiBodHRwczovL2Jvb2tkb3duLm9yZy9yZHBlbmcvUlByb2dEQS9mdW5jdGlvbnMuaHRtbCkKCiogVHV0b3JpYWwgLSBwcmluY2lwYWwgZnVlbnRlIGRlIGVzdGUgYm9va2Rvd24KaHR0cHM6Ly93d3cuYW5hbHl0aWNzdmlkaHlhLmNvbS9ibG9nLzIwMTYvMDQvY29tcGxldGUtdHV0b3JpYWwtdHJlZS1iYXNlZC1tb2RlbGluZy1zY3JhdGNoLWluLXB5dGhvbi8KCiogRWplbXBsbyBkZSDDoXJib2xlcyBkZSBkZWNpc2nDs24KaHR0cHM6Ly93d3cuZ3VydTk5LmNvbS9yLWRlY2lzaW9uLXRyZWVzLmh0bWwKCiogcnBhcnQucGxvdApodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvcnBhcnQucGxvdC9ycGFydC5wbG90LnBkZgoKKiBPcGNpb25lcyBkZSBwbG90ZW8gUnBhcnQgVHJlZQpodHRwOi8vd3d3Lm1pbGJvLm9yZy9ycGFydC1wbG90L3BycC5wZGY=